diff --git a/README.md b/README.md index 208a774b87ecea231883023c36b234b8e78f4145..3cf204a431d5d85f5ec335f61d7404878545d738 100644 --- a/README.md +++ b/README.md @@ -1,164 +1 @@ -This repository will be used as the website for Parallelism and Concurrency CS-206. It will be updated weekly throughout the semester. This README contains general information about the class. - -- [previous-exams](previous-exams) contains PDFs for the previous exams. -- [exercises](exercises) contains markdown documents for exercises and solutions. -- [slides](slides) contains the slides presented in class. -- [labs](labs) contains markdown documents for the labs. - -We will use [piazza.com/epfl.ch/spring2022/cs206](Piazza) as discussion forum. Feel free to open a thread if you have any comments or questions. - -# First-week tasks - -1. Join [the Discord](https://discord.gg/tgbPcCFSm2) -1. Log into gitlab: https://gitlab.epfl.ch/users/sign_in -1. Please fill in [this form](https://forms.gle/N6F3Q3jZm71AASby9) with your GASPAR and SCIPER number -1. Please fill in [this doodle](https://doodle.com/poll/yi2c33zkb8nre3ug) by picking the room in which you will do the exercises. -1. Follow the [Tools Setup](labs/tools-setup.md) page. -1. Do the [example lab](labs/example-lab.md). -1. Watch all videos under *Parallelism 1: Introduction to Parallel Programming* below -1. Do the [first graded lab](labs/lab1-parallel-box-blur-filter/). - -# Grading - -The grading of the course is divided between labs (30%), midterm exam (30%) and final exam (40%). - -# Staff - -| Role | People | -| :--- | :--- | -| Professors | [Martin Odersky](https://people.epfl.ch/martin.odersky), [Kashyap Sanidhya](https://people.epfl.ch/sanidhya.kashyap) | -| TAs | [Dragana Milovancevic](https://people.epfl.ch/dragana.milovancevic), [Matthieu Bovel](https://people.epfl.ch/matthieu.bovel), [Simon Guilloud](https://people.epfl.ch/simon.guilloud), [Tao Lyu](https://people.epfl.ch/tao.lyu), [Gupta Vishal](https://people.epfl.ch/vishal.gupta)| -| Student TAs | Mohamed Boukhari, Martin Lenweiter, Nicolas Matekalo, Tuomas Pääkkönen, Abel Wilkinson | - -# Course Schedule - -Lectures are partially live and partially prerecorded (on YouTube). -Live sessions will be held on Wednesdays from 14:15 to 16:00 if it is a week with live lecture. -Exercise sessions will be held on Wednesdays from 14:15 to 16:00 if it is a week with exercises. -Lab sessions will be held on Wednesdays from 16:15 to 18:00. -You should watch the prerecorded lectures before doing the exercies. - -<!-- seq 0 7 100 | xargs -i date -d "02/24/2021 {} days" +"%d.%m.%Y" --> - -| Week | Date | Topic | Lectures (14:15-16:00) | Exercises (14:15-16:00) | Labs (16:15-18:00) | -| :-- | :-- | :-- | :-- | :-- | :-- | -| 1 | 2022.02.23 | Parallelism 1 | Prerecorded | Welcome session | Lab 1 | -| 2 | 2022.03.02 | Parallelism 2 | Prerecorded | Exercises 1 | Lab 1 & 2 | -| 3 | 2022.03.09 | Parallelism 3 | Prerecorded | Exercises 2 | Lab 2 & 3 | -| 4 | 2022.03.16 | Parallelism 4 | Prerecorded | Exercises 3 | Lab 3 & 4 | -| 5 | 2022.03.23 | Concurrency 1 | Live | None | Lab 4 & 5 | -| 6 | 2022.03.30 | Concurrency 2 | Live | None | Lab 5 & 6 | -| 7 | 2022.04.06 | Concurrency 3 | Live | None | Lab 6 | -| 8 | 2022.04.13 | Concurrency 4 | Live | None | Lab 6 & 7 | -| - | 2022.04.20 | Easter Break | None | None | None | -| 9 | 2022.04.27 | Midterm Exam | Midterm Exam | None | Lab 7 | -| 10 | 2022.05.04 | Futures | Live in CO1 | None | Midterm review | -| 11 | 2022.05.11 | Actors 1 | Prerecorded | Exercises 4 | Lab 8 | -| 12 | 2022.05.18 | Actors 2 | Prerecorded | Exercises 5 | Lab 9 | -| 13 | 2022.05.25 | Actors 3 | Prerecorded | Q&A | Final dry run | - - -Solutions to the exercises are released after each deadline. We do not provide solutions for the labs. - -Before each Exercise session, students should watch videos corresponding to that week's topic: - -### Intro -- [Welcome session (CO1)](slides/CS206 Intro.pdf) - -### Parallelism 1: Introduction to Parallel Programming - -- [Introduction to Parallel Computing](https://www.youtube.com/watch?v=RNVIcm8-6RE&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [Parallelism on the JVM I](https://www.youtube.com/watch?v=ZWJC4pgicK0&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [Parallelism on the JVM II](https://www.youtube.com/watch?v=BKf4X70Oozg&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [Running Computations in Parallel](https://www.youtube.com/watch?v=DbVt8C0-Oe0&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [Monte Carlo Method to Estimate Pi](https://www.youtube.com/watch?v=PLURfYr-rdU&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [First-Class Tasks](https://www.youtube.com/watch?v=gE-JDdxegMc&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [How Fast are Parallel Programs?](https://www.youtube.com/watch?v=kF-15rJ_iPM&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) -- [Benchmarking Parallel Programs](https://www.youtube.com/watch?v=AxqeZ-3jSJ4&list=PLOhKADai-veUWo2cEAJ4JfC9Ssaa9Isbl) - -### Parallelism 2: Basic Task Parallel Algorithms - -- [Parallel Sorting](https://www.youtube.com/watch?v=79LsvRiSWac&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) -- [Data Operations and Parallel Mapping](https://www.youtube.com/watch?v=pZZgG81vROA&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) -- [Parallel Fold (Reduce) Operation](https://www.youtube.com/watch?v=JQxmbpyenko&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) -- [Associativity I](https://www.youtube.com/watch?v=SYNsjfiH53I&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) -- [Associativity II](https://www.youtube.com/watch?v=ggxWa9JvQvY&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) -- [Parallel Scan (Prefix Sum) Operation](https://www.youtube.com/watch?v=0XzO9H20dk0&list=PLOhKADai-veVs9X1yH7QEmAAtohmwbQXs) - -### Parallelism 3: Data-Parallelism - -- [Data-Parallel Programming](https://www.youtube.com/watch?v=Zksc1aEiV_s&list=PLOhKADai-veVfGEHmUShjPwjbmoofbY-N) -- [Data-Parallel Operations I](https://www.youtube.com/watch?v=Nj2gk-IA9OU&list=PLOhKADai-veVfGEHmUShjPwjbmoofbY-N) -- [Data-Parallel Operations II](https://www.youtube.com/watch?v=lXmvqLRftZQ&list=PLOhKADai-veVfGEHmUShjPwjbmoofbY-N) -- [Scala Parallel Operations](https://www.youtube.com/watch?v=pEltisww8BE&list=PLOhKADai-veVfGEHmUShjPwjbmoofbY-N) -- [Splitters and Combiners](https://www.youtube.com/watch?v=p50y6d6UdAk&list=PLOhKADai-veVfGEHmUShjPwjbmoofbY-N) - -### Parallelism 4: Data-Structures for Parallel Computing - -- [Implementing Combiners](https://www.youtube.com/watch?v=q0DtFzMCWe8&list=PLOhKADai-veXBqCTu6IzQ6IG0Me2Fh8ju) -- [Parallel Two-phase Construction](https://www.youtube.com/watch?v=PzHvNEs3gOw&list=PLOhKADai-veXBqCTu6IzQ6IG0Me2Fh8ju) -- [Conc-Tree Data Structure](https://www.youtube.com/watch?v=o0NR9GrcHQo&list=PLOhKADai-veXBqCTu6IzQ6IG0Me2Fh8ju) -- [Amortized, Constant-Time Append Operation](https://www.youtube.com/watch?v=JgX3EZB7Zgs&list=PLOhKADai-veXBqCTu6IzQ6IG0Me2Fh8ju) -- [Conc-Tree Combiners](https://www.youtube.com/watch?v=CumM8JCbmDo&list=PLOhKADai-veXBqCTu6IzQ6IG0Me2Fh8ju) - -### Futures - - [Lecture from 2020](https://www.youtube.com/watch?v=XznYvMjA-7s&t=2499s) - -### Actors 1: The Actor Model - -- [Introduction: why actors?](https://www.youtube.com/watch?v=ZQAe9AItH8o) -- [The Actor Model](https://www.youtube.com/watch?v=c49tDZuFtPA) -- [Message Processing Semantics](https://www.youtube.com/watch?v=Uxn1eg6R0Fc) -- [Designing Actor Systems](https://www.youtube.com/watch?v=uxeMJLo3h9k) -- [Testing Actor Systems](https://www.youtube.com/watch?v=T_2nwLr-H2s) - -### Actors 2: Handling Failure and State - -- [Failure Handling With Actors](https://www.youtube.com/watch?v=tgQuuKUQKxE) -- [Lifecycle Monitoring and The Error Kernel](https://www.youtube.com/watch?v=GYy6mmGXR5E) -- [Persistent Actor State](https://www.youtube.com/watch?v=c-BdLeNxkYk) - -### Actors 3: Distributed Computing - -- [Actors Are Distributed (part 1)](https://www.youtube.com/watch?v=xQx01VDn-jk) -- [Actors Are Distributed (part 2)](https://www.youtube.com/watch?v=LunpgPsYjzQ) -- [Eventual Consistency](https://www.youtube.com/watch?v=Immhr4FKssM) -- [Actor Composition](https://www.youtube.com/watch?v=Ean2-1O9aBs) -- [Scalability](https://www.youtube.com/watch?v=JkcTGRYoZ_A) -- [Responsiveness](https://www.youtube.com/watch?v=KvP-8yrgOr4) - - - -# Labs - -Labs are individual assignments where you get to write Scala programs using the concepts learned during lectures. -Labs are submitted by pushing your code on GitLab, see details in the [grading and submission](labs/grading-and-submission.md) page. - -| Labs | Name | Start date | Due date (23:59 [AoE](https://en.wikipedia.org/wiki/Anywhere_on_Earth)) | -| :-- | :-- | :-- | :-- | -| Lab 1 | Parallel Box Blur Filter | 2022.02.23 | 2022.03.06 | -| Lab 2 | Reductions and Prefix Sums | 2022.03.02 | 2022.03.13 | -| Lab 3 | K-Means | 2022.03.09 | 2022.03.20 | -| Lab 4 | Barnes-Hut Simulation | 2022.03.16 | 2022.03.27 | -| Lab 5 | Concurrent Bounded Buffer | 2022.03.23 | 2022.04.03 | -| Lab 6 | Lock-free sorted list | 2022.03.30 | 2022.04.17 | -| Lab 7 | Hazard Pointer | 2022.04.13 | 2022.05.01 | -| Lab 8 | Actors Binary Tree | 2022.05.11 | 2022.05.23 | -| Lab 9 | Key-Value Store | 2022.05.18 | 2022.06.03 | - -# Exercises - -Exercises are pen and paper style questions that will help you consolidate the knowledge learned during lectures. -Exercises should be done in groups during the lecture. - -# Exams - -The midterm exam will take place on 2022.04.27. The midterm exam will cover all the material seen in the class up to that point. - -The final exam will take place on 2022.06.01. The final exam will cover all material seen during the semester. - -Information about exams organization will be communicated by email. - -[YouTubeConcurrency1]: https://www.youtube.com/watch?v=5oUpSoUoII4 -[YouTubeConcurrency2]: https://www.youtube.com/watch?v=Jvo-vrxaGnk -[YouTubeConcurrency3]: https://www.youtube.com/watch?v=t4tqMzfvclk +Moved to [Moodle](https://moodle.epfl.ch/course/view.php?id=14388). diff --git a/exercises/exercise-1.md b/exercises/exercise-1.md deleted file mode 100644 index 11ddb4aa11efe1c44e106b79516f5bf0b6a6facd..0000000000000000000000000000000000000000 --- a/exercises/exercise-1.md +++ /dev/null @@ -1,124 +0,0 @@ -# Exercise Session 1 - -# Problem 1: Introduction to Concurrency - -Freshly graduated from EPFL, you all have been hired as contractors for a successful and rapidly growing bank. The bank has recently been experiencing problems with their money management system, coded in Scala, and so they hired the best and brightest young engineers they could find: you! The system has been working perfectly fine so far, they tell you. In the past days, due to an increased number of customers, they had to switch from a single threaded sequential execution environment to a multithreaded concurrent environment, in which multiple threads may perform transactions concurrently. That's when problems started, your manager says… - -Below is the code responsible to withdraw money from the account from and transfer it to the account to, within the same bank. - -```scala -def transfer(from: Account, to: Account, amount: BigInt) { - require(amount >= 0) - - val balanceFrom = from.balance - if (balanceFrom >= amount) { - from.balance = balanceFrom - amount - val balanceTo = to.balance - to.balance = balanceTo + amount - } -} -``` - -For the bank, it is very important that the following two properties hold after any sequence of completed transfer transactions: - -1. The balance of an account never goes below 0. -2. The total sum of money held by the bank is constant. - -## Question 1 - -Does the above transfer method respect the two properties in a *sequential* execution environment, that is, when there is only one thread in the program? - -## Question 2 - -What can go wrong in a setting where multiple threads can execute the `transfer` method concurrently? For each of the two desired properties of the system, check if its holds in this concurrent environment. If not, come up with an example execution which exhibits a violation of the property. - -# Question 3 - -For each of the proposed implementations of `transfer` below, check which of the properties hold. Additionally, check if the system is vulnerable to *deadlocks*. - -Variant 1 - -```scala -def transfer(from: Account, to: Account, amount: Long): Unit = { - require(amount >= 0) - - val balanceFrom = from.balance - if (balanceFrom >= amount) { - from.synchronized { - from.balance = balanceFrom - amount - } - to.synchronized { - val balanceTo = to.balance - to.balance = balanceTo + amount - } - } -} -``` - -Variant 2 - -```scala -def transfer(from: Account, to: Account, amount: Long): Unit = { - require(amount >= 0) - - from.synchronized { - val balanceFrom = from.balance - if (balanceFrom >= amount) { - from.balance = balanceFrom - amount - to.synchronized { - val balanceTo = to.balance - to.balance = balanceTo + amount - } - } - } -} -``` - -Variant 3 - -```scala -object lock // Global object -def transfer(from: Account, to: Account, amount: Long): Unit = { - require(amount >= 0) - - lock.synchronized { - val balanceFrom = from.balance - if (balanceFrom >= amount) { - from.balance = balanceFrom - amount - val balanceTo = to.balance - to.balance = balanceTo + amount - } - } -} -``` - -# Problem 2: Parallel Reductions - -## Question 1 - -As a group, write a function called `minMax`, which should take a non-empty array as input and return a pair containing the smallest and the largest element of the array. - -```scala -def minMax(a: Array[Int]): (Int, Int) = ??? -``` - -Now write a parallel version of the function. You may use the constructs `task` and/or `parallel`, as seen in the lectures. - -## Question 2 - -Imagine that the data structure you are given, instead of an `Array[A]`, is one called `ParSeq[A]`. This class offers the two following methods, which work in parallel: - -```scala -def map[B](f: A => B): ParSeq[B] -def reduce(f: (A, A) => A): A -``` - -Can you write the following `minMax` function in terms of `map` and/or `reduce` operations ? - -```scala -def minMax(data: ParSeq[Int]): (Int, Int) = ??? -``` - -## Question 3 - -What property does the function `f` passed to reduce need to satisfy in order to have the same result regardless on how reduce groups the applications of the operation f to the elements of the data structure? Prove that your function `f` indeed satisfies that property. diff --git a/exercises/exercise-2.md b/exercises/exercise-2.md deleted file mode 100644 index 17ba314b7dfb00d9ff36fcc98325c7dd74c3b75f..0000000000000000000000000000000000000000 --- a/exercises/exercise-2.md +++ /dev/null @@ -1,113 +0,0 @@ -# Exercise Session 2 - -# Problem 1: Aggregate - -In this week's lecture, you have been introduced to the aggregate method of `ParSeq[A]` (and other parallel data structures...). It has the following signature: - -```scala -def aggregate[B](z: B)(f: (B, A) => B, g: (B, B) => B): B -``` - -Discuss, as a group, what aggregate does and what its arguments represent. - -## Question 1 - -Consider the parallel sequence `xs` containing the three elements `x1`, `x2` and `x3`. Also consider the following call to aggregate: - -```scala -xs.aggregate(z)(f, g) -``` - -The above call might potentially result in the following computation: - -```scala -f(f(f(z, x1), x2), x3) -``` - -But it might also result in other computations. Come up with at least 2 other computations that may result from the above call to `aggregate`. - -## Question 2 - -Below are other examples of calls to aggregate. In each case, check if the call can lead to different results depending on the strategy used by `aggregate` to aggregate all values contained in `data` down to a single value. You should assume that `data` is a parallel sequence of values of type `BigInt`. - -Variant 1 - -```scala -data.aggregate(1)(_ + _, _ + _) -``` - -Variant 2 - -```scala -data.aggregate(0)((acc, x) => x - acc, _ + _) -``` - -Variant 3 - -```scala -data.aggregate(0)((acc, x) => acc - x, _ + _) -``` - -Variant 4 - -```scala -data.aggregate(1)((acc, x) => x * x * acc, _ * _) -``` - -## Question 3 - -Under which condition(s) on `z`, `f`, and `g` does aggregate always lead to the same result? -Come up with a formula on `z`, `f`, and `g` that implies the correctness of aggregate. - -*Hint*: You may find it useful to use calls to `foldLeft(z)(f)` in your formula(s). - -## Question 4 - -Implement `aggregate` using the methods `map` and/or `reduce` of the collection you are defining aggregate for. - -## Question 5 - -Implement `aggregate` using the `task` and/or `parallel` constructs seen in the first week and the `Splitter[A]` interface seen in this week's lecture. The `Splitter` interface is defined as: - -```scala -trait Splitter[A] extends Iterator[A] { - def split: Seq[Splitter[A]] - def remaining: Int -} -``` - -You can assume that the data structure you are defining aggregate for already implements a `splitter` method which returns an object of type `Splitter[A]`. - -Your implementation of `aggregate` should work in parallel when the number of remaining elements is above the constant THRESHOLD and sequentially below it. - -*Hint*: `Iterator`, and thus `Splitter`, implements the `foldLeft` method. - -## Question 6 - -Discuss the implementations from questions 4 and 5. Which one do you think would be more efficient? - -# Problem 2: Depth - -Review the notion of depth seen in the lecture. What does it represent? - -Below is a formula for the depth of a *divide and conquer* algorithm working on an array segment of *size L*, as a function of *L*. The values *c*, *d* and *T* are constants. We assume that *L>0* and *T>0*. - - - -Below the threshold *T*, the algorithm proceeds sequentially and takes time *c* to process each single element. Above the threshold, the algorithm is applied recursively over the two halves of the array. The results are then merged using an operation that takes *d* units of time. - -## Question 1 - -Is it the case that for all *1 ≤ L1 ≤ L2* we have *D(L1) ≤ D(L2)*? - -If it is the case, prove the property by induction on *L*. If it is not the case, give a counterexample showing values of *L1*, *L2*, *T*, *c*, and *d* for which the property does not hold. - -## Question 2 - -Prove a logarithmic upper bound on *D(L)*. That is, prove that *D(L)* is in *O(log(L))* by finding specific constants *a*, *b* such that *D(L) ≤ a * log2(L) + b*. - -*Hint:* The proof is more complex that it might seem. One way to make it more manageable is to define and use a function *D'(L)* that has the property described in question 1, and is greater or equal to *D(L)*. We suggest you use: - - - -Also remark that computing *D'(L)* when *L* is a power of 2 is easy. Also remember that there always exists a power of 2 between any positive integer and its double. diff --git a/exercises/exercise-3.md b/exercises/exercise-3.md deleted file mode 100644 index 4909c30588fee0118dd9085beaf91bb276075e0c..0000000000000000000000000000000000000000 --- a/exercises/exercise-3.md +++ /dev/null @@ -1,123 +0,0 @@ -# Exercise Session 3 - -## Problem 1: Parallel Encoding - -In this exercise, your group will devise a parallel algorithm to encode sequences using the run-length encoding scheme. This encoding transforms sequences of letters such that all subsequences of the same letter are replaced by the letter and the sequence length. For instance: - -``` -"AAAAATTTGGGGTCCCAAC" ⇒ "A5T3G4T1C3A2C1" -``` - -Your goal in this exercise is to come up with a parallel implementation of this algorithm. The function should have the following shape: - -```scala -def rle(data: ParSeq[Char]): Buffer[(Char, Int)] = - data.aggregate(???)(???, ???) -``` - -The Buffer class is already given to you. A buffer of type `Buffer[A]` represents sequences of elements of type `A`. It supports the following methods, all of which are efficient: - -```scala -def isEmpty: Boolean // Checks if the buffer is empty. -def head: A // Returns the first element of the buffer. -def tail: Buffer[A] // Returns the buffer minus its first element. -def last: A // Returns the last element of the buffer. -def init: Buffer[A] // Returns the buffer minus its last element. -def ++(that: Buffer[A]): Buffer[A] // Concatenate two buffers. -def append(elem: A): Buffer[A] // Appends a single element to the right. - -Buffer.empty[A]: Buffer[A] // Returns an empty buffer. -Buffer.singleton[A](element: A): Buffer[A] // Single element buffer. -``` - -## Problem 2: Parallel Two Phase Construction - -In this exercise, you will implement an array Combiner using internally a double linked list (DLL). Below is a minimal implementation of the `DLLCombiner` class and the related `Node` class. Your goal for this exercise is to complete the implementation of the (simplified) Combiner interface of the `DLLCombiner` class. - -```scala -class DLLCombiner[A] extends Combiner[A, Array[A]]: - var head: Node[A] = null // null for empty lists. - var last: Node[A] = null // null for empty lists. - var size: Int = 0 - - // Implement these three methods... - override def +=(elem: A): Unit = ??? - override def combine(that: DLLCombiner[A]): DLLCombiner[A] = ??? - override def result(): Array[A] = ??? - -class Node[A](val value: A): - var next: Node[A] // null for last node. - var previous: Node[A] // null for first node. -``` - -**Question 1:** What computational complexity do your methods have? Are the actual complexities of your methods acceptable according to the `Combiner` requirements? - -**Question 2:** One of the three methods you have implemented, `result`, should work in parallel according to the `Combiner` contract. Can you think of a way to implement this method efficiently using 2 parallel tasks? - -**Question 3:** Can you, given the current internal representation of your combiner, implement `result` so that it executes efficiently using 4 parallel tasks? If not, can you think of a way to make it possible? - -*Hint:* This is an open-ended question, there might be multiple solutions. In your solution, you may want to add extra information to the class Node and/or the class DLLCombiner. - -## Problem 3: Pipelines - -In this exercise, we look at pipelines of functions. A pipeline is simply a function which applies its argument successively to each function of a sequence. To illustrate this, consider the following pipeline of 4 functions: - -```scala -val p: Int => Int = toPipeline(ParSeq(_ + 1, _ * 2, _ + 3, _ / 4)) -``` - -The pipeline `p` is itself a function. Given a value `x`, the pipeline `p` will perform the following computations to process it. In the above example, - -```scala -p(x) = (((x + 1) Application of first function - * 2) Application of second function - + 3) Application of third function - / 4 Application of fourth function -``` - -In this exercise, we will investigate the possibility to process such pipelines in parallel. - -**Question 1:** Implement the following `toPipeline` function, which turns a parallel sequence of functions into a pipeline. You may use any of the parallel combinators available on `ParSeq`, such as the parallel `fold` or the parallel `reduce` methods. - -```scala -def toPipeline(fs: ParSeq[A => A]): A => A = ??? -``` - -*Hint:* Functions have a method called andThen, which implements function composition: it takes as argument another function and also returns a function. The returned function first applies the first function, and then applies the function passed as argument to that result. You may find it useful in your implementation of pipeline. - -**Question 2:** Given that your `toPipeline` function works in parallel, would the pipelines it returns also work in parallel? Would you expect pipelines returned by a sequential implementation of toPipeline to execute any slower? If so, why? - -Discuss those questions with your group and try to get a good understanding of what is happening. - -**Question 3:** Instead of arbitrary functions, we will now consider functions that are constant everywhere except on a finite domain. We represent such functions in the following way: - -```scala -class FiniteFun[A](mappings: immutable.Map[A, A], default: A): - def apply(x: A): A = - mappings.get(x) match - case Some(y) => y - case None => default - - def andThen(that: FiniteFun[A]): FiniteFun[A] = ??? -``` - -Implement the andThen method. Can pipelines of such finite functions be efficiently constructed in parallel using the appropriately modified `toPipeline` method? Can the resulting pipelines be efficiently executed? - -**Question 4:** Compare the *work* and *depth* of the following two functions, assuming infinite parallelism. For which kind of input would the parallel version be asymptotically faster? - -```scala -def applyAllSeq[A](x: A, fs: Seq[FiniteFun[A]]): A = - // Applying each function sequentially. - var y = x - for f <- fs do - y = f(y) - y - -def applyAllPar[A](x: A, fs: ParSeq[FiniteFun[A]]): A = - if fs.isEmpty then x - else - // Computing the composition in parallel. - val p = fs.reduce(_ andThen _) - // Applying the pipeline. - p(x) -``` diff --git a/exercises/exercise-4.md b/exercises/exercise-4.md deleted file mode 100644 index cb1a551e6dcd2cd6764a773246ad20580df55c1b..0000000000000000000000000000000000000000 --- a/exercises/exercise-4.md +++ /dev/null @@ -1,94 +0,0 @@ -# Exercise Session 4 - -## Problem 1: Implementing `map` and `filter` on Futures - -In this exercise, you will come up with an implementation of the `map` and `filter` methods of `MyFuture`. The `MyFuture` trait is a simplified version of the `Future` trait from the Scala standard library, with a single abstract method: - -```scala -trait MyFuture[+T]: - def onComplete(callback: Try[T] => Unit): Unit -``` - -First of all, spend some time as a group to make sure that you understand what those methods are supposed to do. Then, complete the following code to implement the two methods: - -```scala -extension [T](self: MyFuture[T]) - def map[S](f: T => S): MyFuture[S] = ??? - def filter(p: T => Boolean): MyFuture[T] = ??? -``` - -In the case of `filter`, if the original `MyFuture` successfully returns a value which does not satisfy the predicate, the new `MyFuture` should return a `Failure` containing a `NoSuchElementException`. - -See: -- [`Try` API documentation](https://dotty.epfl.ch/api/scala/util/Try.html) -- [`Future` API documentation](https://dotty.epfl.ch/api/scala/concurrent/Future.html) -- [Futures and Promises guide](https://docs.scala-lang.org/overviews/core/futures.html) - -## Problem 2: Coordinator / Worker - -In this exercise, you will implement a Coordinator / Worker actor system, in which one actor, the coordinator, dispatches work to other actors, the workers. Between the coordinator and the workers, only two kinds of messages are sent: `Request` and `Ready` messages. - -```scala -enum Message: - case Request(computation: () => Unit) - case Ready -``` - -<details> - <summary><em>Note:</em> <code>enum</code> syntax</summary> - -Enumerations are the Scala 3 idiomatic syntax to define algebraic data -types (ADTs). The code below is desugared to something equivalent to: - -```scala -trait Message -case class Request(computation: () => Unit) extends Message -object Ready extends Message -``` - -which is the syntax used in the lecture videos. - -See: -- [Translation of Enums and ADTs]( - https://docs.scala-lang.org/scala3/reference/enums/desugarEnums.html) -- [Enums slides from CS210](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/slides/progfun1-4-4.pdf) - -</details> - ---- - -The coordinator actor sends `Request` messages to workers to request them to perform some computation (passed as an argument of `Request`). Upon reception of a `Request`, a worker should perform the computation. Workers should send a `Ready` message to their coordinator whenever they finish executing the requested computation, and also right after they are created. - -The coordinator actor itself receives requests through `Request` messages from clients. The coordinator actor should then dispatch the work to worker actors. The coordinator should however never send a request to a worker which has not declared itself ready via a `Ready` message beforehand. - -Implement the `Coordinator` and `Worker` classes. - -```scala -class Coordinator extends Actor: - ??? - override def receive = ??? - -class Worker(coordinator: Coordinator) extends Actor: - ??? - override def receive = ??? -``` - -An example system using the `Coordinator` and `Worker` actors is shown below. - -```scala -@main def problem2 = new TestKit(ActorSystem("coordinator-workers")) with ImplicitSender: - try - val coordinator = system.actorOf(Props(Coordinator()), "coordinator") - val workers = Seq.tabulate(4)(i => - system.actorOf(Props(Worker(coordinator)), f"worker$i") - ) - - // Now, clients should be able to send requests to the coordinator… - coordinator ! Request(() => println(3 + 5)) - coordinator ! Request(() => println(67 * 3)) - // And so on... - finally shutdown(system) - -``` - -*Hint*: In order to fulfill its job, the coordinator should remember which workers are ready and what requests are still to be allocated to a worker. diff --git a/exercises/exercise-4.pdf b/exercises/exercise-4.pdf deleted file mode 100644 index 04977b3ad554cab8b79183d65e504a9e2b3cafff..0000000000000000000000000000000000000000 Binary files a/exercises/exercise-4.pdf and /dev/null differ diff --git a/exercises/exercise-5.md b/exercises/exercise-5.md deleted file mode 100644 index 963e2ec22f1395fa955ec8bcc5efe7a5606efa12..0000000000000000000000000000000000000000 --- a/exercises/exercise-5.md +++ /dev/null @@ -1,134 +0,0 @@ -# Exercise Session 5 - -## Problem 1: Message Processing Semantics - -Consider the following actor system: - -```scala -enum Protocol: - case Write(value: Int) - case Read(requester: ActorRef) -import Protocol.* - -enum Responses: - case Answer(value: Int) -import Responses.* - -class Memory extends Actor: - var value = 0 - - override def receive: Receive = { - case Write(newValue) => value = newValue - case Read(requester) => requester ! Answer(value) - } - -class Client(memory: ActorRef) extends Actor: - override def receive: Receive = { case Answer(value) => - println(value) - } - -class MyProxy(memory: ActorRef) extends Actor: - override def receive: Receive = { case message => - memory ! message - } -``` - -### Problem 1.1 - -And the following test: - -```scala -@main def problem1_1 = - for _ <- 1 to 1000 do - val system = ActorSystem("example") - try - val memory = system.actorOf(Props(Memory())) - val client = system.actorOf(Props(Client(memory))) - memory ! Read(client) - memory ! Write(1) - finally system.terminate() -``` - -What are the possible values printed by the `println` command in the `Client` actor? Why? - -### Problem 1.2 - -Now, consider the following test: - -```scala -@main def problem1_2 = - for _ <- 1 to 1000 do - val system = ActorSystem("example") - try - val memory = system.actorOf(Props(Memory())) - val proxy = system.actorOf(Props(MyProxy(memory))) - val client = system.actorOf(Props(Client(memory))) - proxy ! Read(client) - memory ! Write(1) - finally system.terminate() -``` - -1. What are the possible values printed by the `println` command in the `Client2` actor? Why? -2. Would the output be different if the `Read` and `Write` messages were issued in the other order? -3. What if both messages are sent through the `Proxy` actor? - - -## Problem 2: The Josephus Problem - -In this exercise, we will revisit the famous [*Josephus problem*](https://en.wikipedia.org/wiki/Josephus_problem). In this problem, a group of soldiers trapped by the enemy decide to commit suicide instead of surrendering. In order not to have to take their own lives, the soldiers devise a plan. All soldiers are arranged in a single circle. Each soldier, when it is their turn to act, has to kill the next soldier alive next to them in the clockwise direction. Then, the next soldier that is still alive in the same direction acts. This continues until there remains only one soldier in the circle. This last soldier is the lucky one, and can surrender if he decides to. The *Josephus problem* consists in finding the position in the circle of this lucky soldier, depending on the number of soldiers. - -In this exercise, you will implement a *simulation* of the mass killing of the soldiers. Each soldier will be modeled by an actor. Soldiers are arranged in a circle and when their turn comes to act, they kill the next alive soldier in the circle. The next soldier that is still alive in the circle should act next. The last soldier remaining alive does not kill himself but prints out its number to the standard output. - -The code below covers the creation of all actors and the initialization of the system. Your goal is to implement the `receive` method of `Soldier`. - -*Hint:* Think about what state the soldier must have. - -```scala -import akka.actor.* - -object Soldier: - // The different messages that can be sent between the actors: - enum Protocol: - - // The recipient should die. - case Death - - // The recipient should update its next reference. - case Next(next: ActorRef) - - // The recipient should act. - case Act - -class Soldier(number: Int) extends Actor: - import Soldier.* - import Protocol.* - - def receive: Receive = behavior(None, None, false) - - def behavior( - next: Option[ActorRef], - killer: Option[ActorRef], - mustAct: Boolean - ): Receive = ??? - -@main def problem2(n: Int) = - import Soldier.* - import Soldier.Protocol.* - - // Initialization - val system = ActorSystem("mySystem") - require(n >= 1) - - // Creation of the actors. - val actors = Seq.tabulate(n)( - (i: Int) => system.actorOf(Props(classOf[Soldier], i), "Soldier" + i) - ) - - // Inform all actors of the next actor in the circle. - for i <- 0 to (n - 2) do actors(i) ! Next(actors(i + 1)) - actors(n - 1) ! Next(actors(0)) - - // Inform the first actor to start acting. - actors(0) ! Act - -``` diff --git a/exercises/exercise-5.pdf b/exercises/exercise-5.pdf deleted file mode 100644 index 511481fd625a623c61cd44795cf9bed9068c75d6..0000000000000000000000000000000000000000 Binary files a/exercises/exercise-5.pdf and /dev/null differ diff --git a/exercises/images/2-1.png b/exercises/images/2-1.png deleted file mode 100644 index b527b78472c6021df5f712d9806b71d0d46add33..0000000000000000000000000000000000000000 Binary files a/exercises/images/2-1.png and /dev/null differ diff --git a/exercises/images/2-2.png b/exercises/images/2-2.png deleted file mode 100644 index f436cbb79777c392a4e848f7ad53de6fd840d5ad..0000000000000000000000000000000000000000 Binary files a/exercises/images/2-2.png and /dev/null differ diff --git a/exercises/solutions-1.md b/exercises/solutions-1.md deleted file mode 100644 index 69ee5c54823c42fdccbf74b0ccc7029273de3c0f..0000000000000000000000000000000000000000 --- a/exercises/solutions-1.md +++ /dev/null @@ -1,98 +0,0 @@ -# Exercise 1 : Introduction to Concurrency - -## Question 1 - -Yes - -## Question 2 - -#### Property 1 holds - -Assuming that the execution of two concurrent threads only interleaves instructions and that reads and writes are executed atomically, it can be shown that property 1 always holds. Unfortunately, such strong guarantees are not offered by the Java Memory Model. If you are interested, have a look at the note below on the Java Memory Model. - -#### Violation of property 2 - -Consider 2 threads that execute concurrently `transfer(from, to, amount)` with the exact same parameters. Assume that the account from has sufficient funds for at least one transfer. - -Thread 1 executes until it has computed the value balanceFrom - amount and then stops. Thread 2 then executes in its entirety the call to `transfer(from, to, amount)`. Then thread 1 resumes its execution and completes the call to `transfer`. - -At the end of this execution, the total amount of money held by the bank has changed. It has in fact increased by the value amount. - -#### Note on the Java Memory Model - -Assuming the Java Memory Model, both of the two properties can potentially be violated. Indeed, the model only ensures that the execution of each thread appears sequential to the thread itself, and not to any other concurrently running threads. Seemingly atomic instructions can be arbitrarily decomposed by the underlying virtual machine. Sequences of instructions can also be reordered at will by the VM, as long as the execution of a single thread appears as if it were executed sequentially. In these settings, both properties can be violated. - -## Question 3 - -Variant 1 - -In this variant, property 2 can be violated. It is not vulnerable to deadlocks. - -Variant 2 - -In this variant, none of the two properties can be violated. However, it is susceptible to deadlocks. - -Variant 3 - -In this last variant, none of the two properties can be violated and no deadlock can occur. It is however still not entirely satisfactory, since no two threads can execute transfers in parallel, even when the accounts are totally disjointed. Can you think of a better solution? - -## Question 1 - -```scala -def minMax(a: Array[Int]): (Int, Int) = { - val threshold = 10 - - def minMaxPar(from: Int, until: Int): (Int, Int) = { - - if (until - from <= threshold) { - var i = from - var min = a(from) - var max = a(from) - - while (i < until) { - val x = a(i) - if(x < min) min = x - if(x > max) max = x - i = i + 1 - } - - (min, max) - } else { - val mid = from + ((until - from) / 2) - val ((xMin, xMax), - (yMin, yMax)) = parallel(minMaxPar(from, mid), - minMaxPar(mid, until)) - (min(xMin, yMin), max(xMax, yMax)) - } - } - - minMaxPar(0, a.size) -} -``` - -## Question 2 - -```scala -def minMax(data: ParSeq[Int]): (Int, Int) = data.map({ - (x: Int) => (x, x) -}).reduce({ - case ((mn1, mx1), (mn2, mx2)) => (min(mn1, mn2), max(mx1, mx2)) -}) -``` - -Or: - -```scala -def minMax(data: ParSeq[Int]): (Int, Int) = - (data.reduce(min), data.reduce(max)) -``` - -## Question 3 - -The function `f` must be associative. That is, for any `x`, `y`, `z`, it should be the case that: - -``` -f(x, f(y, z)) == f(f(x, y), z). -``` - -Both the `min` and `max` functions are associative. In addition, it can be easily shown that pairwise application of associative functions is also associative. From this follows that `f` is indeed associative. diff --git a/exercises/solutions-2.md b/exercises/solutions-2.md deleted file mode 100644 index 99da85c42282b3217e738422bc1127fdeae98002..0000000000000000000000000000000000000000 --- a/exercises/solutions-2.md +++ /dev/null @@ -1,135 +0,0 @@ -# Exercise 1 : Aggregate - -## Question 1 - -- g(f(z, x1), f(f(z, x2), x3)) -- g(f(f(z, x1), x2), f(z, x3)) -- g(g(f(z, x1), f(z, x2)), f(z, x3)) -- g(f(z, x1), g(f(z, x2), f(z, x3))) - -## Question 2 - -Variant 1 - -This might lead to different results. - -Variant 2 - -This might lead to different results. - -Variant 3 - -This always leads to the same result. - -Variant 4 - -This always leads to the same result. - -## Question 3 - -A property that implies the correctness is: - -``` -forall xs, ys. g(xs.F, ys.F) == (xs ++ ys).F (split-invariance) -``` - -where we define - -``` -xs.F == xs.foldLeft(z)(f) -``` - -The intuition is the following. Take any computation tree for -`xs.aggregate`. Such a tree has internal nodes labelled by g and segments processed using `foldLeft(z)(f)`. The split-invariance law above says that any internal g-node can be removed by concatenating the segments. By repeating this transformation, we obtain the entire result equals `xs.foldLeft(z)(f)`. - -The split-invariance condition uses `foldLeft`. The following two conditions together are a bit simpler and imply split-invariance: - -``` -forall u. g(u,z) == u (g-right-unit) -forall u, v. g(u, f(v,x)) == f(g(u,v), x) (g-f-assoc) -``` - -Assume g-right-unit and g-f-assoc. We wish to prove split-invariance. We do so by induction on the length of `ys`. If ys has length zero, then `ys.foldLeft` gives `z`, so by g-right-unit both sides reduce to xs.foldLeft. Let `ys` have length `n>0` and assume by I.H. split-invariance holds for all `ys` of length strictly less than `n`. Let `ys == ys1 :+ y` (that is, y is the last element of `ys`). Then - -``` -g(xs.F, (ys1 :+ y).F) == (foldLeft definition) -g(xs.F, f(ys1.F, y)) == (by g-f-assoc) -f(g(xs.F, ys1.F), y) == (by I.H.) -f((xs++ys1).F, y) == (foldLeft definition) -((xs++ys1) :+ y).F == (properties of lists) -(xs++(ys1 :+ y)).F -``` - -## Question 4 - -```scala -def aggregate[B](z: B)(f: (B, A) => B, g: (B, B) => B): B = - if (this.isEmpty) z - else this.map((x: A) => f(z, x)).reduce(g) -``` - -## Question 5 - -```scala -def aggregate(z: B)(f: (B, A) => B, g: (B, B) => B): B = { - - def go(s: Splitter[A]): B = { - if (s.remaining <= THRESHOLD) - s.foldLeft(z)(f) - else { - val splitted = s.split - - val subs = splitted.map((t: Splitter[A]) => task { go(t) }) - subs.map(_.join()).reduce(g) - } - } - - go(splitter) -} -``` - -## Question 6 - -The version from question 4 may require 2 traversals (one for `map`, one for `reduce`) and does not benefit from the (potentially faster) sequential operator `f`. - -# Exercise 2 : Depth - -## Question 1 - -Somewhat counterintuitively, the property doesn't hold. To show this, let's take the following values for *L1*, *L2*, *T*, *c*, and *d*. - -``` -L1 = 10, L2 = 12, T = 11, c = 1, and d = 1. -``` - -Using those values, we get that: - -``` -D(L1) = 10 -D(L2) = max(D(6), D(6)) + 1 = 7 -``` - -## Question 2 - -*Proof sketch* - -Define the following function D'(L). - - - -Show that *D(L) ≤ D'(L)* for all *1 ≤ L*. - -Then, show that, for any *1 ≤ L1 ≤ L2* we have *D'(L1) ≤ D'(L2)*. This property can be shown by induction on *L2*. - -Finally, let *n* be such that *L ≤ 2n < 2L*. We have that: - -``` -D(L) ≤ D'(L) Proven earlier. - ≤ D'(2n) Also proven earlier. - ≤ log2(2n) (d + cT) + cT - < log2(2L) (d + cT) + cT - = log2(L) (d + cT) + log2(2) (d + cT) + cT - = log2(L) (d + cT) + d + 2cT -``` - -Done. diff --git a/exercises/solutions-3.md b/exercises/solutions-3.md deleted file mode 100644 index fffd7a7f2ef21434cb44fd6962188881f46c0f00..0000000000000000000000000000000000000000 --- a/exercises/solutions-3.md +++ /dev/null @@ -1,170 +0,0 @@ -# Exercise Session 3, Solutions - -## Problem 1: Parallel Encoding - -```scala -def rle(data: ParSeq[Char]): Buffer[(Char, Int)] = - def g(as: Buffer[(Char, Int)], bs: Buffer[(Char, Int)]) = - if as.isEmpty || bs.isEmpty || as.last._1 != bs.head._1 then - as ++ bs - else - as.init.append((as.last._1, as.last._2 + bs.head._2)) ++ bs.tail - - def f(acc: Buffer[(Char, Int)], x: Char) = - if acc.isEmpty || acc.last._1 != x then - acc.append((x, 1)) - else - acc.init.append((x, acc.last._2 + 1)) - - val z: Buffer[(Char, Int)] = Buffer.empty - - data.aggregate(z)(f, g) -``` - -## Problem 2: Parallel Two Phase Construction - - -```scala -class DLLCombiner[A] extends Combiner[A, Array[A]] - var head: Node[A] = null - var last: Node[A] = null - var size: Int = 0 - - override def +=(elem: A): Unit = - val node = new Node(elem) - if size == 0 then - head = node - last = node - size = 1 - else - last.next = node - node.previous = last - last = node - size += 1 - - override def combine(that: DLLCombiner[A]): DLLCombiner[A] = - if this.size == 0 then - that - else if that.size == 0 then - this - else - this.last.next = that.head - that.head.previous = this.last - - this.size = this.size + that.size - this.last = that.last - - this - - // This is not implemented in parallel yet. - override def result(): Array[A] = - val data = new Array[A](size) - - var current = head - var i = 0 - while i < size do - data(i) = current.value - i += 1 - current = current.next - data -``` - -### Question 1 - -The complexity of `+=` is constant, as well as the complexity of `combine`. This is obviously well within the desired complexity range. The result function takes time linear in the size of the data, which is acceptable according to the Combiner requirements. However, the result function should work in parallel according to the contract. This isn't the case here. - - -### Question 2 - -The idea is to copy the double linked list to the array from both ends at the same time. For this, we create a task that handles the second half of the array, while the current thread copied the first half. - -```scala -override def result(): Array[A] = - val data = new Array[A](size) - val mid = size / 2 - - // This is executed on a different thread. - val taskEnd = task { - var i = size - 1 - var current = last - while i >= mid do - data(i) = current.value - current = current.previous - i -= 1 - } - - // This is executed on the current thread. - var i = 0 - var current = head - while i < mid do - data(i) = current.value - current = current.next - i += 1 - taskEnd.join() - data -``` - -### Question 3 - -The actual answer to this question is: *it depends*. Two see why, we first make the following observation: - -All implementations of the result function must consist of primarily two operations: -1. Moving to the next node in the list, and, -2. Copying the value of the node to the array. - -Depending on the actual cost of the two operations, one may devise schemes that can make efficient use of more than two threads. For instance, assume for a moment that copying a value to the array is significantly costlier than moving to the next node in the list. In this case, we could execute the function efficiently in parallel by spawning multiple threads starting from the head of the list, each handling a disjoint set of indexes (for instance, one thread takes indexes of the form 4n, another 4n + 1 and so on). - -On the other hand, if we assume that moving to the next node in the list has a cost comparable to the one of copying a value to the array, then finding such a strategy is more challenging, or even impossible. - -However, there are ways to circumvent this problem by modifying the data structure used. One way could be to keep track of the middle of the double linked lists. The result function could then execute in parallel on 4 different threads by copying the array from both ends and from the middle (in both directions) simultaneously. The problem would then be to efficiently maintain the pointer to the middle of the list, which might not be a trivial task when combining arbitrary lists together. If you are interested in learning more about such data-structures, we encourage you to look up the skip list data structure, which generalises on this idea. - -Another solution would be to modify the nodes so that they also point to their successor's successor and their predecessor's predecessor. This way, two threads could start from the start of the list and two from the end. In each case, one thread would be responsible for odd indexes and the other for even ones. This solution does not change at all the complexity of the various Combiner operations, but requires a bit more bookkeeping. - - -## Problem 3: Pipelines - -### Question 1 - -```scala -def toPipeline(fs: ParSeq[A => A]): A => A = - if (fs.isEmpty) - (x: A) => x - else - fs.reduce(_ andThen _) -``` - -### Question 2 - -Even though the pipeline is constructed in parallel, *it will not itself execute in parallel*. The resulting pipeline still has to apply its argument to all the functions it contains sequentially. This is due to the fact that the andThen method simply returns a function that will apply the first function and then the second, sequentially. - -### Question 3 - -```scala -def andThen(that: FiniteFun[A]): FiniteFun[A] = { - val newDefault = that(default) - - val newMappings = for - (x, y) <- mappings - val z = that(y) - if (z != newDefault) - yield (x, z) - - FiniteFun(newMappings, newDefault) -} -``` - -Pipelines of such functions can be efficiently constructed in parallel, as was the case for "normal" functions also. Also, interestingly, the resulting pipeline can be executed efficiently. The execution time of the pipeline does not depend on the number of functions in the pipeline, only on the lookup time in the finite map mappings (which can be nearly constant time if the underlying map is a hashtable). The size of this map is upper bounded by the size of the mappings of the functions in the pipeline. - -### Question 4 - -To simplify the analysis, we will assume that lookup in the mappings takes constant time, and thus that applying a FiniteFun also takes constant time. Let's also assume that fs is of size `n` for both functions. - -Since the function is purely sequential, the work and depth of applyAllSeq are equal. They amount to `n` applications of a finite function, which is linear in `n`. - -For applyAllPar, things are a bit more complex. Let's denote by `d` the size of the largest domain of all functions passed as argument. - -The depth of the function is simply the depth of computing the pipeline (`fs.reduce(_ andThen _)`) plus a constant for applying the pipeline. Assuming infinite parallelism, this results in a depth that is in `O(log2(n) ⋅ d)`. - -The work of applyAllPar is significantly more than its depth, and can be upper bounded by `O(n ⋅ d)`. Indeed, there are `n` applications of the `andThen` method, each of which takes `O(d)` time. - -When `d` is a constant, then the parallel version will be asymptotically faster than its sequential counterpart. If `d` is exponentially larger than `n`, then the sequential version is expected to perform better. diff --git a/exercises/solutions-4/.gitignore b/exercises/solutions-4/.gitignore deleted file mode 100644 index cc92d252fed98e77240201d6120a9b74cb66665a..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.vscode -.metals -.bloop -.bsp -target -metals.sbt -build.properties -project/project diff --git a/exercises/solutions-4/.scalafmt.conf b/exercises/solutions-4/.scalafmt.conf deleted file mode 100644 index 1cea5243def8047a81295a8b13cb970660e0b3fc..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/.scalafmt.conf +++ /dev/null @@ -1,4 +0,0 @@ -version = "3.4.0" -runner.dialect = scala3 -rewrite.scala3.convertToNewSyntax = true -rewrite.scala3.removeOptionalBraces = true diff --git a/exercises/solutions-4/Readme.md b/exercises/solutions-4/Readme.md deleted file mode 100644 index 28b78174dc24ddad1a642eac71bd873b61501ab6..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/Readme.md +++ /dev/null @@ -1,4 +0,0 @@ -# Exercise Session 4, Solutions - -- Problem 1: [Problem1.scala](src/main/scala/Problem1.scala) and [Problem1Test.scala](src/test/scala/Problem1Test.scala) -- Problem 2: [Problem2.scala](src/main/scala/Problem2.scala) diff --git a/exercises/solutions-4/build.sbt b/exercises/solutions-4/build.sbt deleted file mode 100644 index 9865ad5b4683b009fb6b2a820e5368c86adfb891..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/build.sbt +++ /dev/null @@ -1,22 +0,0 @@ -val scala3Version = "3.1.2" -val akkaVersion = "2.6.19" - -lazy val root = project - .in(file(".")) - .settings( - name := "code", - version := "0.1.0-SNAPSHOT", - scalaVersion := scala3Version, - fork := true, - javaOptions ++= Seq( - "-Dakka.loglevel=Debug", - "-Dakka.actor.debug.receive=on" - ), - libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-actor" % akkaVersion, - "com.typesafe.akka" %% "akka-testkit" % akkaVersion, - "junit" % "junit" % "4.13" % Test, - "com.github.sbt" % "junit-interface" % "0.13.3" % Test - ), - Test / testOptions += Tests.Argument(TestFrameworks.JUnit) - ) diff --git a/exercises/solutions-4/project/plugins.sbt b/exercises/solutions-4/project/plugins.sbt deleted file mode 100644 index 83adafa3f1dc8a82b2f18ba573029a8f1ca4cc72..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") diff --git a/exercises/solutions-4/src/main/scala/Problem1.scala b/exercises/solutions-4/src/main/scala/Problem1.scala deleted file mode 100644 index a86a8f358e5702142d139cb59d346f81bd9a36fd..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/src/main/scala/Problem1.scala +++ /dev/null @@ -1,28 +0,0 @@ -import scala.util.{Try, Success, Failure} -import scala.concurrent.ExecutionContext -import java.util.concurrent.Future -import java.util.concurrent.atomic.AtomicReference - -// Test using `sbt "testOnly Problem1Test"` -// See tests in Problem1Test.scala - -trait MyFuture[+T]: - def onComplete(callback: Try[T] => Unit): Unit - -extension [T](self: MyFuture[T]) - def map[S](f: T => S): MyFuture[S] = - new MyFuture: - def onComplete(callback: Try[S] => Unit): Unit = - self.onComplete { - case Success(v) => callback(Success(f(v))) - case Failure(e) => callback(Failure(e)) - } - def filter(p: T => Boolean): MyFuture[T] = - new MyFuture: - def onComplete(callback: Try[T] => Unit): Unit = - self.onComplete { - case Success(v) => - if p(v) then callback(Success(v)) - else callback(Failure(new NoSuchElementException())) - case Failure(e) => callback(Failure(e)) - } diff --git a/exercises/solutions-4/src/main/scala/Problem2.scala b/exercises/solutions-4/src/main/scala/Problem2.scala deleted file mode 100644 index 8ab4f787875459c64de56dbf2fbe5ab5392476e7..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/src/main/scala/Problem2.scala +++ /dev/null @@ -1,72 +0,0 @@ -import akka.actor.{Actor, Props, ActorSystem, ActorRef, ActorLogging} -import akka.testkit.{TestKit, ImplicitSender} -import akka.event.LoggingReceive - -// Run using `sbt "runMain problem2"` - -/** Type of messages exchanged between our Actors. - * - * Note: enumerations are the Scala 3 idiomatic syntax to define algebraic data - * types (ADTs). The code below is desugared to something equivalent to: - * - * ``` - * trait Message - * case class Request(computation: () => Unit) extends Message - * object Ready extends Message - * ``` - * - * which is the syntax used in the lecture videos. - * - * Read also: - * - Translation of Enums and ADTs: - * https://docs.scala-lang.org/scala3/reference/enums/desugarEnums.html - * - Enums slides from CS210: - * https://gitlab.epfl.ch/lamp/cs210/-/blob/master/slides/progfun1-4-4.pdf - */ -enum Message: - case Request(computation: () => Unit) - case Ready -import Message.* - -class Coordinator extends Actor: - var availableWorkers: List[ActorRef] = Nil - var pendingRequests: List[Request] = Nil - - override def receive = LoggingReceive { - case Ready => - if pendingRequests.isEmpty then - availableWorkers = availableWorkers :+ sender() - else - val request = pendingRequests.head - pendingRequests = pendingRequests.tail - sender() ! request - case request: Request => - availableWorkers match - case worker :: rest => - worker ! request - availableWorkers = rest - case Nil => - pendingRequests = pendingRequests :+ request - } - -class Worker(coordinator: ActorRef) extends Actor: - coordinator ! Ready - - override def receive: Receive = LoggingReceive { case Request(f) => - f() - coordinator ! Ready - } - -@main def problem2 = new TestKit(ActorSystem("coordinator-workers")) - with ImplicitSender: - try - val coordinator = system.actorOf(Props(Coordinator()), "coordinator") - val workers = Seq.tabulate(4)(i => - system.actorOf(Props(Worker(coordinator)), f"worker$i") - ) - - // Now, clients should be able to send requests to the coordinator… - coordinator ! Request(() => println(3 + 5)) - coordinator ! Request(() => println(67 * 3)) - // And so on... - finally shutdown(system) diff --git a/exercises/solutions-4/src/test/scala/Problem1Test.scala b/exercises/solutions-4/src/test/scala/Problem1Test.scala deleted file mode 100644 index 920c2c8d438618ce9e17a3ac980bf32af2ceeed5..0000000000000000000000000000000000000000 --- a/exercises/solutions-4/src/test/scala/Problem1Test.scala +++ /dev/null @@ -1,52 +0,0 @@ -import scala.util.{Try, Success, Failure} -import org.junit.Test -import org.junit.Assert.{assertEquals, fail} - -class Problem1Test: - object MyFuture: - final def successful[T](value: T): MyFuture[T] = - new MyFuture: - def onComplete(callback: Try[T] => Unit): Unit = - callback(Success(value)) - - final def failed[T](error: Error): MyFuture[T] = - new MyFuture: - def onComplete(callback: Try[T] => Unit): Unit = - callback(Failure(error)) - - @Test - def mapWorksWithSuccess() = - MyFuture.successful(3).map(_ + 1).onComplete { - case Success(value) => assertEquals(4, value) - case _ => fail("Expected result to be a Success") - } - - @Test - def mapWorksWithFailure() = - val error = new Error("Some error") - MyFuture.failed[Int](error).map(_ + 1).onComplete { - case Failure(actualError) => assertEquals(error, actualError) - case _ => fail("Expected result to be a Failure") - } - - @Test - def filterWorksWithSuccessNotFilteredOut() = - MyFuture.successful(3).filter(_ == 3).onComplete { - case Success(value) => assertEquals(3, value) - case _ => fail("Expected result to be a Failure") - } - - @Test - def filterWorksWithSuccessFilteredOut() = - MyFuture.successful(3).filter(_ == 4).onComplete { - case Failure(actualError: NoSuchElementException) => () - case _ => fail("Expected result to be a NoSuchElementException exception") - } - - @Test - def filterWorksWithFailure() = - val error = new Error("Some error") - MyFuture.failed[Int](error).filter(_ == 3).onComplete { - case Failure(actualError) => assertEquals(error, actualError) - case _ => fail("Expected result to be a Failure") - } diff --git a/exercises/solutions-5/.gitignore b/exercises/solutions-5/.gitignore deleted file mode 100644 index cc92d252fed98e77240201d6120a9b74cb66665a..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.vscode -.metals -.bloop -.bsp -target -metals.sbt -build.properties -project/project diff --git a/exercises/solutions-5/.scalafmt.conf b/exercises/solutions-5/.scalafmt.conf deleted file mode 100644 index 1cea5243def8047a81295a8b13cb970660e0b3fc..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/.scalafmt.conf +++ /dev/null @@ -1,4 +0,0 @@ -version = "3.4.0" -runner.dialect = scala3 -rewrite.scala3.convertToNewSyntax = true -rewrite.scala3.removeOptionalBraces = true diff --git a/exercises/solutions-5/Readme.md b/exercises/solutions-5/Readme.md deleted file mode 100644 index a1885584f2c5daf2e923d7c4be20932038d31848..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/Readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# Exercise Session 5, Solutions - -## Problem 1: Message Processing Semantics - -### Problem 1.1 - -For the `Client1` actor, the only possible output is `0`. The reason is that messages between two actors are guaranteed to be received in the order they were sent. - -You can try the code yourself by running: -``` -sbt "runMain problem1_1" -``` - -### Problem 1.2 - -1. For the `Client2` actor, either `0` or `1` can be printed. There are no restrictions on the order in which messages are processed in this case. It might be the case that the `Memory` actor receives the `Write` message from the `Client2` first, or the `Read` message from the `Proxy` first. - -2. The order in which the messages are sent by the `Client2` doesn't change the possible behaviours of the system. - -3. In the case both messages are sent through the `Proxy`, then the only possible output is `0`, since in this case the messages between the `Client2` and `Proxy`, as well as between `Proxy` and `Memory`, are guaranteed to be handled in the same order they were sent. - -You can try the code yourself by running: -``` -sbt "runMain problem1_2" -``` - -## Problem 2 - -The solution is in `Problem2.scala`. - -You can run it using: - -``` -sbt "runMain problem2 10" -``` diff --git a/exercises/solutions-5/build.sbt b/exercises/solutions-5/build.sbt deleted file mode 100644 index 0aed4e0a5e70090991d53bc8cc333cba5385ac8e..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/build.sbt +++ /dev/null @@ -1,25 +0,0 @@ -val scala3Version = "3.1.2" -val akkaVersion = "2.6.19" - -lazy val root = project - .in(file(".")) - .settings( - name := "code", - version := "0.1.0-SNAPSHOT", - scalaVersion := scala3Version, - fork := true, - javaOptions ++= Seq( - "-Dakka.loglevel=Info", - "-Dakka.actor.allow-java-serialization=on" - ), - libraryDependencies ++= Seq( - "org.scalameta" %% "munit" % "1.0.0-M3" % Test, - "com.typesafe.akka" %% "akka-actor" % akkaVersion, - "com.typesafe.akka" %% "akka-testkit" % akkaVersion, - "com.typesafe.akka" %% "akka-persistence" % akkaVersion, - // SLF4J backend - // See https://doc.akka.io/docs/akka/current/typed/logging.html#slf4j-backend - "ch.qos.logback" % "logback-classic" % "1.2.11" - ), - Test / testOptions += Tests.Argument(TestFrameworks.JUnit) - ) diff --git a/exercises/solutions-5/project/plugins.sbt b/exercises/solutions-5/project/plugins.sbt deleted file mode 100644 index 83adafa3f1dc8a82b2f18ba573029a8f1ca4cc72..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") diff --git a/exercises/solutions-5/src/main/scala/Problem1.scala b/exercises/solutions-5/src/main/scala/Problem1.scala deleted file mode 100644 index 2b055846cbba0a02e3e58ae92f8621eed4b110f2..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/src/main/scala/Problem1.scala +++ /dev/null @@ -1,56 +0,0 @@ -import scala.util.{Try, Success, Failure} -import scala.concurrent.ExecutionContext -import java.util.concurrent.Future -import java.util.concurrent.atomic.AtomicReference -import akka.actor.* -import akka.testkit.* -import akka.event.LoggingReceive - -enum Protocol: - case Write(value: Int) - case Read(requester: ActorRef) -import Protocol.* - -enum Responses: - case Answer(value: Int) -import Responses.* - - -class Memory extends Actor: - var value = 0 - - override def receive: Receive = { - case Write(newValue) => value = newValue - case Read(requester) => requester ! Answer(value) - } - -class Client(memory: ActorRef) extends Actor: - override def receive: Receive = { case Answer(value) => - println(value) - } - -class MyProxy(memory: ActorRef) extends Actor: - override def receive: Receive = { case message => - memory ! message - } - -@main def problem1_1 = - for _ <- 1 to 1000 do - val system = ActorSystem("example") - try - val memory = system.actorOf(Props(Memory())) - val client = system.actorOf(Props(Client(memory))) - memory ! Read(client) - memory ! Write(1) - finally system.terminate() - -@main def problem1_2 = - for _ <- 1 to 1000 do - val system = ActorSystem("example") - try - val memory = system.actorOf(Props(Memory())) - val proxy = system.actorOf(Props(MyProxy(memory))) - val client = system.actorOf(Props(Client(memory))) - proxy ! Read(client) - memory ! Write(1) - finally system.terminate() diff --git a/exercises/solutions-5/src/main/scala/Problem2.scala b/exercises/solutions-5/src/main/scala/Problem2.scala deleted file mode 100644 index d198ffef1c4c89b6e909319145cd2f7f0c10a852..0000000000000000000000000000000000000000 --- a/exercises/solutions-5/src/main/scala/Problem2.scala +++ /dev/null @@ -1,86 +0,0 @@ -import akka.actor.* -import akka.testkit.TestKit - -object Soldier: - // The different messages that can be sent between the actors: - enum Protocol: - - // The recipient should die. - case Death - - // The recipient should update its next reference. - case Next(next: ActorRef) - - // The recipient should act. - case Act - -class Soldier(number: Int) extends Actor: - import Soldier.* - import Protocol.* - - def receive: Receive = behavior(None, None, false) - - def behavior( - next: Option[ActorRef], - killer: Option[ActorRef], - mustAct: Boolean - ): Receive = { - - case Death => - next match - case Some(myNext) => - sender() ! Next(myNext) - myNext ! Act - println("Soldier " + number + " dies.") - self ! PoisonPill - - case None => - context.become( - behavior(next = None, killer = Some(sender()), mustAct = mustAct) - ) - - case Next(newNext) => - if newNext == self then println("Soldier " + number + " is last !") - else if !killer.isEmpty then - killer.get ! Next(newNext) - newNext ! Act - println("Soldier " + number + " dies.") - self ! PoisonPill - else if mustAct then - newNext ! Death - context.become(behavior(next = None, killer = None, mustAct = false)) - else - context.become( - behavior(next = Some(newNext), killer = None, mustAct = false) - ) - - case Act => - next match - case Some(myNext) => - myNext ! Death - context.become( - behavior(next = None, killer = killer, mustAct = false) - ) - - case None => - context.become(behavior(next = None, killer = killer, mustAct = true)) - } - -@main def problem2(n: Int) = new TestKit(ActorSystem()): - import Soldier.* - import Soldier.Protocol.* - - // Initialization - require(n >= 1) - - // Creation of the actors. - val actors = Seq.tabulate(n)( - (i: Int) => system.actorOf(Props(classOf[Soldier], i), "Soldier" + i) - ) - - // Inform all actors of the next actor in the circle. - for i <- 0 to (n - 2) do actors(i) ! Next(actors(i + 1)) - actors(n - 1) ! Next(actors(0)) - - // Inform the first actor to start acting. - actors(0) ! Act diff --git a/final/CO_1_numbered.pdf b/final/CO_1_numbered.pdf deleted file mode 100644 index 73dc08a23d73adb08b07ded89c4fec923e713fa8..0000000000000000000000000000000000000000 Binary files a/final/CO_1_numbered.pdf and /dev/null differ diff --git a/final/INF_1_numbered.pdf b/final/INF_1_numbered.pdf deleted file mode 100644 index 2bb5756691d0a299c76e78e84a8a1b93ef78b028..0000000000000000000000000000000000000000 Binary files a/final/INF_1_numbered.pdf and /dev/null differ diff --git a/final/INF_2_numbered.pdf b/final/INF_2_numbered.pdf deleted file mode 100644 index 0cd07748eb97db2f2429ae6b189461e333808578..0000000000000000000000000000000000000000 Binary files a/final/INF_2_numbered.pdf and /dev/null differ diff --git a/final/dry-run/Readme.md b/final/dry-run/Readme.md deleted file mode 100644 index b6fb049ae84bd4c9fd312d4dbde100b51bdfc420..0000000000000000000000000000000000000000 --- a/final/dry-run/Readme.md +++ /dev/null @@ -1,2 +0,0 @@ -- Empty handouts and instructions: <https://gitlab.epfl.ch/lamp/cs206/-/tree/master/previous-exams/2021-final>. -- Solutions: <https://gitlab.epfl.ch/lamp/cs206/-/tree/master/previous-exams/2021-final-solutions> diff --git a/final/final_seats.csv b/final/final_seats.csv deleted file mode 100644 index a54d0d20d1b9eab5a2924babc2a658f107e390af..0000000000000000000000000000000000000000 --- a/final/final_seats.csv +++ /dev/null @@ -1,265 +0,0 @@ -SCIPER,ROOM,IDINROOM -238038,INF 1,34 -242532,CO 1,47 -260389,CO 1,60 -264015,INF 1,13 -265615,CO 1,111 -271837,CO 1,4 -275503,CO 1,99 -281885,CO 1,104 -289080,CO 1,15 -289207,INF 1,3 -296098,CO 1,69 -296169,INF 1,20 -296729,INF 2,39 -296782,CO 1,61 -297111,INF 2,13 -298689,INF 2,27 -299489,INF 1,6 -300325,INF 2,5 -300570,CO 1,108 -300882,CO 1,43 -301062,INF 2,15 -301317,CO 1,116 -301650,CO 1,5 -301681,INF 1,7 -301995,CO 1,71 -302186,INF 1,47 -302446,INF 1,51 -302505,CO 1,88 -302560,CO 1,65 -307877,INF 2,42 -309994,INF 1,17 -310041,INF 2,46 -310052,INF 1,60 -310068,CO 1,18 -310095,CO 1,23 -310108,INF 2,1 -310274,CO 1,6 -310298,CO 1,13 -310427,CO 1,125 -310502,CO 1,34 -310668,INF 2,34 -310698,CO 1,42 -310713,INF 2,45 -310725,CO 1,56 -310755,INF 2,57 -310766,CO 1,38 -310781,INF 2,58 -310821,CO 1,80 -310824,INF 1,23 -310890,CO 1,59 -310917,CO 1,25 -311055,CO 1,35 -311258,CO 1,140 -311259,INF 2,18 -311475,INF 2,7 -311480,INF 2,53 -311528,INF 1,12 -311751,CO 1,130 -311768,CO 1,1 -312107,INF 1,8 -312119,CO 1,118 -312275,CO 1,67 -312276,CO 1,138 -312360,CO 1,16 -312533,CO 1,84 -312589,CO 1,32 -312622,CO 1,90 -312711,CO 1,83 -312734,INF 2,62 -312752,INF 1,61 -312859,CO 1,31 -312905,INF 1,29 -312916,INF 1,46 -312917,CO 1,139 -313191,INF 1,49 -313206,CO 1,10 -313215,CO 1,17 -313234,CO 1,94 -313238,CO 1,112 -313240,CO 1,53 -313336,INF 1,26 -313364,INF 1,16 -313369,CO 1,3 -313830,CO 1,117 -314316,CO 1,102 -314355,INF 2,9 -314357,CO 1,103 -314363,INF 1,32 -314372,CO 1,96 -314412,CO 1,50 -314517,CO 1,131 -314540,CO 1,77 -314544,INF 1,1 -314770,CO 1,33 -314932,INF 2,4 -314947,CO 1,7 -314994,INF 1,38 -315031,INF 1,41 -315131,INF 2,14 -315202,INF 2,32 -315213,CO 1,79 -315337,INF 1,50 -315349,CO 1,137 -315363,CO 1,86 -315429,CO 1,126 -315644,INF 2,54 -315666,CO 1,64 -315707,CO 1,70 -315751,CO 1,27 -315789,INF 2,3 -315805,INF 2,55 -315822,CO 1,134 -316129,CO 1,73 -316383,INF 2,28 -316447,INF 1,56 -316482,INF 2,61 -316555,CO 1,105 -316641,INF 1,5 -316766,CO 1,97 -320195,CO 1,52 -324074,INF 2,11 -324214,INF 2,10 -324253,CO 1,68 -324268,INF 2,48 -324363,INF 2,47 -324402,INF 1,39 -324406,CO 1,115 -324420,CO 1,39 -324448,INF 2,21 -324456,CO 1,93 -324479,INF 2,30 -324509,INF 1,21 -324604,CO 1,78 -324610,INF 1,10 -324622,CO 1,28 -324665,CO 1,120 -324694,CO 1,21 -324748,CO 1,24 -324855,INF 1,55 -324875,CO 1,29 -324915,CO 1,107 -324932,INF 2,44 -324944,INF 2,19 -325035,INF 2,43 -325084,INF 1,37 -325090,CO 1,85 -325174,INF 1,9 -325180,CO 1,128 -325186,CO 1,37 -325205,INF 2,6 -325279,CO 1,75 -325341,CO 1,20 -325374,INF 2,40 -325375,CO 1,19 -325395,INF 2,22 -325403,CO 1,62 -325510,CO 1,127 -325529,INF 1,53 -325664,CO 1,11 -325708,CO 1,30 -325734,INF 2,29 -325736,INF 2,26 -325758,INF 2,60 -325765,INF 1,35 -325917,CO 1,91 -325969,INF 1,18 -326051,CO 1,55 -326153,CO 1,26 -326177,INF 2,37 -326295,INF 1,11 -326324,CO 1,63 -326410,INF 1,62 -326423,CO 1,110 -326432,INF 1,36 -326450,CO 1,98 -326464,CO 1,45 -326580,INF 2,33 -326601,INF 2,24 -326603,INF 1,54 -326608,CO 1,95 -326615,INF 2,36 -326617,CO 1,46 -326634,INF 2,25 -326678,INF 2,20 -326801,CO 1,9 -326846,INF 2,49 -326912,INF 1,22 -326913,CO 1,87 -326940,INF 1,43 -326960,CO 1,2 -327033,INF 2,56 -327059,CO 1,36 -327085,CO 1,121 -327224,CO 1,135 -327230,INF 1,59 -327282,CO 1,114 -327327,CO 1,22 -327345,INF 2,41 -327503,CO 1,100 -327529,INF 1,40 -327577,INF 1,2 -327579,CO 1,58 -327668,INF 2,59 -327830,CO 1,74 -328055,INF 2,50 -328086,INF 1,4 -328105,INF 1,57 -328129,CO 1,8 -328132,CO 1,49 -328387,INF 2,12 -328401,INF 1,45 -328453,CO 1,133 -328523,INF 2,52 -328777,INF 1,25 -329197,INF 1,15 -329307,CO 1,12 -329346,CO 1,136 -329500,CO 1,129 -329516,INF 1,24 -329571,CO 1,76 -329597,INF 1,31 -329619,INF 1,42 -329637,INF 2,38 -329651,INF 1,33 -329672,CO 1,44 -329797,CO 1,14 -329806,CO 1,57 -329847,CO 1,92 -329880,CO 1,54 -329905,CO 1,132 -329912,CO 1,106 -329953,CO 1,41 -329977,INF 1,19 -329978,INF 1,44 -330163,INF 2,35 -330275,CO 1,123 -330298,INF 1,14 -330316,CO 1,66 -330361,INF 2,16 -330382,INF 2,8 -330383,INF 1,30 -330564,CO 1,122 -330682,INF 2,51 -330757,CO 1,48 -330818,CO 1,113 -337347,INF 2,31 -341453,CO 1,51 -341911,INF 1,48 -342296,INF 2,23 -344883,CO 1,40 -346110,INF 1,58 -349182,CO 1,81 -349231,CO 1,101 -349286,CO 1,89 -349290,CO 1,82 -349310,INF 2,17 -350464,CO 1,119 -350467,INF 1,28 -350499,INF 1,52 -350606,CO 1,124 -350622,INF 1,27 -350642,CO 1,109 -351003,INF 2,2 -351364,CO 1,72 diff --git a/final/instructions/README.md b/final/instructions/README.md deleted file mode 100644 index cd3dba4c46e2971679d11a569d25effd42a7e144..0000000000000000000000000000000000000000 --- a/final/instructions/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# CS-206: Final Exam - -Wednesday, 1 June 2022, 16:15 - 18:45 - -Rooms: INF1, INF2, CO1. seating plan at https://gitlab.epfl.ch/lamp/cs206/-/tree/master/final - -**If <https://gitlab.epfl.ch> is not responding, use <https://ic-gitlab.epfl.ch>.** - -*Exam rooms are equipped with computer plugs. Students must bring their own laptops that are capable of developing and locally testing assignments such as labs done during the semester. As a student, it is your responsibility to ensure that you have access to reliable hardware and software for the duration of the exam. Please make sure that you are comfortable using the usual tools from the class, so that you can focus on the exam. If you have trouble assuring access to a laptop and are willing to work with a rented one, please contact us ASAP and we will explore if we can get you one to use during the exam.* - -This is an open-book exam. For example, you are allowed to consult the PDF slides for all lectures in this course and the Functional Programming course and do Google search. The final exam will cover all the material seen during the semester. - -*No cheating*: Each student must solve the exam individually. Consulting with anyone except the teaching staff of this course during the exam, copying solutions from the Internet, or making your solution available to anyone is considered cheating and a reason for disciplinary action. Make sure that any non-relevant application, in particular social networks and chat apps are closed before coming to the exam. Having those open at any point may be considered cheating. - -The exam consists of four programming assignments that you should solve using the usual tools from the class (git, sbt, and your favorite text editor). In addition to problem statements, each problem comes with a set of automated tests, just like for the labs. Those tests will be the main component used to compute your grade. Make sure to follow any additional requirements listed in the problem statement. The teaching staff may manually inspect and grade part of your code. Each question has a total of 250 points, split between tests. - -You should submit your answers by pushing your code to GitLab. Don't forget to push regularly, typically between every question. At the end of the exam, you will have an additional 15 minutes to make sure that your solutions are uploaded and to handle any potential technical difficulties. Commits pushed after 19:00 will not count for the exam. - -## How to obtain questions - - -We have prepared each assignment similarly to labs: the problem statements are markdown files in the directory <https://gitlab.epfl.ch/lamp/cs206/-/tree/master/final/instructions>: - -- [Problem 1: Combiners](concpar22final01.md) -- [Problem 2: Wait and Notify](concpar22final02.md) -- [Problem 3: Futures](concpar22final03.md) -- [Problem 4: Actors](concpar22final04.md) - -The code skeleton for each problem is in a separate branch of your private GitLab repository. - -## How to submit your solutions - -You should submit your solutions by pushing your code to GitLab, just like for the labs. After you submit your solution, you will receive a preliminary grade for that question based on automated tests only. This information will be available in the GitLab CI. The tests executed on the CI are identical to those you can run locally. For detailed information, refer to lab submission instructions: https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/grading-and-submission.md#committing-and-pushing-your-code. - -You are allowed to push multiple times the solution of a question. Only the last commit within the deadline will be considered for your grade. - -## How to run tests on your laptop - -Refer to labs submission instructions for detailed information on how to run tests on your laptop: https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/grading-and-submission.md#local-tests-and-grading - -## Recommended workflow summary - -After you obtained a question, do the following: - -1. read the requirements carefully -2. write the solution taking the requirements into account -3. make sure that your solution compiles -4. make sure that your solution passes the local tests on your machine; if it does not, repeat previous steps -5. submit your solution using git -6. start working on another question - -You can solve questions in any order. If you conclude that you have spent some time on the question and you estimate that you will likely not solve it, then go to step 6 to get a chance at solving other questions. - -## How we grade your exam - -Each question is worth 250 points. If you do not manage to solve a particular question, you can skip to another one. You will get some points for partially correct solutions, as indicated in the grader output. An entire question can never receive a negative number of points; the least amount of points is zero. - -You need to push your code to GitLab to receive a grade. If you forget to submit a solution before 19:00, you will receive zero points for that question. - -## Hardware setup - -We expect that the exam can be completed reasonably on a laptop with around 14" screen, 1920x1080 resolution, and a reasonable CPU and RAM, such that the price (with Windows or Linux OS) remains under 1000 CHF. You are allowed to bring an external keyboard and a mouse. You are not allowed to use any other screen than your laptop's (this includes laptop screens, external monitors, tablets such as ipads and others, or phones, to give a few examples). We ask you to turn off your mobile devices during the exam. If you need multiple power sockets during the exam, please bring a socket strip with a straight plug (not a 90 degree one), as we are only guaranteeing to provide one socket per one student. - -We do not provide wired ethernet and expect you to use EPFL WiFi network, which will be available. Please test your setup at EPFL, including the WiFi connection, before the exam. Do not change your hardware setup during the exam, unless it becomes absolutely necessary for you to continue the work. We advise you to keep your setup as robust and simple as possible and focus on solving the questions. - -If you anticipate difficulties in arranging your computer setup for the exam according to the above instructions, please contact us immediately to discuss possible solutions. - diff --git a/final/instructions/concpar22final01.md b/final/instructions/concpar22final01.md deleted file mode 100644 index 7b8d10edb0840450839c58cce991cc49b973db49..0000000000000000000000000000000000000000 --- a/final/instructions/concpar22final01.md +++ /dev/null @@ -1,102 +0,0 @@ -# Problem 1: Combiners - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar22final01 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar22final01 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Exercise - -In this exercise, you will implement an array Combiner. The Combiner internally uses a double linked list whose nodes also point to their successor's successor and their predecessor's predecessor. Your goal is to complete the implementation of the (simplified) Combiner interface, by implementing the `result` method to compute the result array from this array combiner. - -Here you can see the declaration of the `DLLCombiner` class and the related `Node` class definition. Look at the `Lib` trait in the `lib.scala` file to find all definitions of relevant functions and classes. - -```scala - class Node(val value: Int): - protected var next: Node = null // null for last node. - protected var next2: Node = null // null for last node. - protected var previous: Node = null // null for first node. - protected var previous2: Node = null // null for first node. - - def getNext: Node = next // do NOT use in the result method - def getNext2: Node = next2 - def getPrevious: Node = previous // do NOT use in the result method - def getPrevious2: Node = previous2 - - def setNext(n: Node): Unit = next = n - def setNext2(n: Node): Unit = next2 = n - def setPrevious(n: Node): Unit = previous = n - def setPrevious2(n: Node): Unit = previous2 = n - - - // Simplified Combiner interface - // Implements methods `+=` and `combine` - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner -``` - -`DLLCombiner` class contains the implementation of methods `+=` and `combine`. You should look at them to better understand the structure of this array Combiner, before moving on to solving this exercise. - -Your task in the exercise will be to implement the `result` method of the `DLLCombinerImplementation` class. This method should compute the result array from this array combiner. In your solution, you should **not** use methods `getNext` and `getPrevious`, but only `getNext2` and `getPrevious2`, to reduce the number of moving operations. - -According to the Combiner contract, `result` should work in parallel. Implement this method efficiently using 4 parallel tasks, by copying the double linked list to the array from both ends at the same time. Two threads should start from the start of the list and two from the end. In each case, one thread would be responsible for odd indexes and the other for even ones. - -Following the description above, your task in the exercise is to: - - 1. Implement the four tasks to copy parts of the resulting array. Each task is responsible for copying one quarter of the array: - - `task1` copies every other Integer element of data array, starting from the first (index 0), up to the middle - - `task2` copies every other Integer element of data array, starting from the second, up to the middle - - `task3` copies every other Integer element of data array, starting from the second to last, up to the middle - - `task4` copies every other Integer element of data array, starting from the last, up to the middle - 2. Implement the method `result` to compute the result array in parallel using those four tasks. - - Here is one example of the `result` method: - -```scala - val combiner1 = new DLLCombinerImplementation - combiner1 += 7 - combiner1 += 2 - combiner1 += 4 - combiner1 += 3 - combiner1 += 9 - combiner1 += 5 - combiner1 += 1 - - val res1 = combiner1.result() // (7, 2, 4, 3, 9, 5, 1) -``` -In this example, `task1` was responsible for copying elements at indexes 0 and 2, `task2` for copying the element at index 1, `task3` for copying elements at indexes 5 and 3, and `task4` for copying element at indexes 6 and 4. - -Here is another example with combining: - -```scala - val c1 = new DLLCombinerImplementation - c1 += 7 - c1 += 2 - c1 += 4 - c1 += 3 - c1 += 9 - c1 += 5 - c1 += 1 - - val c2 = new DLLCombinerImplementation - c2 += 6 - c2 += 8 - c2 += 5 - c2 += 1 - - val c3 = new DLLCombinerImplementation - c3 += 1 - - c1.combine(c2).combine(c3) - val res = c1.result() // (7, 2, 4, 3, 9, 5, 1, 6, 8, 5, 1, 1) -``` - -You can get partial points for solving parts of this exercise. -In your solution you should only make changes to the `DLLCombinerImplementation` class. You are not allowed to change the file `lib.scala`. diff --git a/final/instructions/concpar22final02.md b/final/instructions/concpar22final02.md deleted file mode 100644 index 59dc15cb56c474ee823914cf0d38024460f14ece..0000000000000000000000000000000000000000 --- a/final/instructions/concpar22final02.md +++ /dev/null @@ -1,38 +0,0 @@ -# Problem 2: Wait and Notify - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar22final02 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar22final02 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Problem 2.1: Implement Barrier methods - -Your first task is to implement a _barrier_. A barrier acts as a synchronization point between multiple threads. It is used when you want all threads to finish a task before starting the next one. - -You have to complete the following two methods in the `Barrier` class: -1. `awaitZero` function waits for the count value to be zero. -2. `countDown` function decrements the count by one. It notifies other threads if count is less than or equal to zero. - -The barrier will be implemented using these functions. When the thread finish a task, it will decrement the count by using the `countDown` function. Then, it will call the `awaitZero` function to wait for other threads. - -## Problem 2.2: Use the Barrier to apply filters to an image - -In this part, each thread will apply an array of filters to each row of the image. Your task is to use the `Barrier` to act as a synchronization point while applying the filters. Each thread should wait for the other threads to complete the current filter before applying the next filter. - -`ImageLib.scala` provides an implementation of an image processing library with different filters. Each filter has a kernel which is applied on the image. `ImageLib.scala` implements four different filters. It provides an `applyFilter` method which applies a particular filter's kernel on a particular row on the input `Array` and generates the output in the output `Array`. - -The `ImageLib` class takes the size of an image as input. The image is a square matrix. The class has two buffers `buffer1` and `buffer2`. The initial image will be in `buffer1`. For the filtering task, you will switch between these buffers as input and output. For example, for the first filter `buffer1` will the input buffer and `buffer2` will be the output buffer. For the second filter `buffer2` will the input and `buffer1` will be the output and so on for subsequent filters. - -In `Problem2.scala` file where you will complete the `imagePipeline` function: - -- The `imagePipeline` function gets a array of filters and an array of row numbers. This filter needs to be applied to all the rows present in `row` array. After applying each filter, the thread has to wait for other threads to complete before applying the next filter. You will use barrier in this case. -- The `imagePipeline` function will return the output buffer. Note the output buffer can change between `buffer1` and `buffer2` depending on the number of filters applied. - -You can get partial points for solving parts of this exercise. diff --git a/final/instructions/concpar22final03.md b/final/instructions/concpar22final03.md deleted file mode 100644 index 84cea5e6c1d7fb4342b615e54cb7b9fa3d57323e..0000000000000000000000000000000000000000 --- a/final/instructions/concpar22final03.md +++ /dev/null @@ -1,37 +0,0 @@ -# Problem 3: Futures - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar22final03 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar22final03 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Exercise - -The famous trading cards game Scala: The Programming has recently been gaining traction. -In this little exercise, you will propose to clients your services as a trader: Buying and selling cards in groups on demand. - -You are provided in the file `Economics.scala` with an interface to handle asynchronous buying and selling of cards and management of your money. Do not modify this file. More precisely, this interface defines: - -- A `Card`, which has a `name` and which you can own (`isMine == true`) or not (`isMine == false`). This is only to prevent a card from being sold or used multiple times, and you may not need it. You can find the value of a card using `valueOf`. -- A `MoneyBag`, which is a container to transport money. Similarly, the money inside a bag can only be used once. The function `moneyIn` informs you of the bag's value, should you need it. -- The function `sellCard`, which will sell a card through a `Future` and gives you back a `Future[MoneyBag]`. If you do not own the card, the `Future` will fail. -- The function `buyCard`, which will consume a given `MoneyBag` and handle you, through a `Future`, the requested card. The provided bag must contain the exact amount of money corresponding to the card's value. -- Finally, you have a bank account with the following functions: - - `balance`: indicates your current monetary possession - - `withdraw`: substracts a given amount from your balance, and handles you a corresponding `Future[MoneyBag]` - - `deposit`: consumes a moneyBag and returns a `Future[Unit]` when the balance is updated. Note that you should not deposit empty moneyBags! If you do, you will get a failure, possibly indicating that you try to deposit the same bag twice. - -Your task in the exercise is to implement the function `orderDeck` in the file `Problem3.scala`. In a `Future`, start by checking that the sum of the money and the value of the cards the client gives you is large enough to buy the requested list of cards. If it is not, then the future should fail with a `NotEnoughMoneyException`. - -Then, sell all provided cards and put the received moneyBags in your bank accounts by chaining asynchronously the `Futures` of `sellCard` and `deposit`. You will obtain a `List[Future[Unit]]`, which should be converted into a `Future[Unit]` (so that when this `Future` returns, all deposits have finished). Those steps are provided for you in the helper function `sellListOfCards`. - -Then, do the opposite: withdraw `MoneyBags` of adequate value and use them to buy cards. Finally agregate the `List[Future[Card]]` into a `Future[List[Card]]`. You can implement those steps into the `buyListOfCards` function. Take inspiration from the given example `sellListOfCards`, and combine them in the `orderDeck` function. - -Final tip: Make good use of `map`, `flatMap` and `zip` on futures. diff --git a/final/instructions/concpar22final04.md b/final/instructions/concpar22final04.md deleted file mode 100644 index e9d1942a02a6b37fa6c06917be83c9d450abcaa3..0000000000000000000000000000000000000000 --- a/final/instructions/concpar22final04.md +++ /dev/null @@ -1,98 +0,0 @@ -# Problem 4: Implementing Spotify using actors - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar22final04 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar22final04 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Useful Links - -- [Akka Classic documentation](https://doc.akka.io/docs/akka/current/index-classic.html), in particular: - - [Classic Actors](https://doc.akka.io/docs/akka/current/actors.html) - - [Testing Classic Actors](https://doc.akka.io/docs/akka/current/testing.html) - - [Classic Logging](https://doc.akka.io/docs/akka/current/logging.html) -- [Akka Classic API reference](https://doc.akka.io/api/akka/current/akka/actor/index.html) -- [CS206 slides](https://gitlab.epfl.ch/lamp/cs206/-/tree/master/slides) - -## Overview - -In this exercise, you will implement the core functionalities of an online music streaming service. Users will be modelled as individual Akka actors. - -- Each user has a unique identifier and a name. -- Each user can like and unlike songs (stored in the user's _liked songs_ list). Liked songs are sorted by reverse date of liking time (the last liked song must be the first element of the list). Elements of this list must be unique: a song can only be liked once. Liking a song twice should not impact the order. -- Each user can subscribe and unsubscribe to other users to see what they are listening to. This is stored in the user's _activity feed_. The items in the activity feed are sorted by reverse date of activity time (the last added activity must be the first element of the list). Items in this list should be unique by user. If a new activity with a user that is already in the list is added, the former should be removed, so that we always see the latest activity for each user we have subscribed to. You can assume that there is a single actor and `ActorRef` per user. - -This corresponds to the core features of Spotify: - - - -Your task is to implement the receive method of the `User` actor. See the enums in the `User` what messages and responses a `User` should handle. - -You are allowed to add private methods and attributes to the `User` class. You can also import any Scala collection you might find useful. - -To implement the last part (problem 4.4), you will need to interact with the `SongStore` actor passed as the `songStore` parameter. You do not need it for the other parts. - -## Problem 4.1: Getting user info (50 points) - -Your first task is to implement the `User.receive` method so that it handles the `GetInfo` and `GetHomepageData` messages. This will allow you to pass the first 2 tests. - -## Problem 4.2: Updating user info (70 points) - -Your second task is to expand `User.receive` so that it handles the `Like` and `Unlike` messages. - -## Problem 4.3: Updating user info (70 points) - -Your third task is to expand `User.receive` so that it handles the `Subscribe`, `Unsubscribe`, `AddActivity` and `Play` messages. - -## Problem 4.4: Displaying the homepage (60 points) - -Your last (but not least!) task is to expand `User.receive` so that it handles the `GetHomepageText` message. - -A `GetHomepageText` should be answered with `HomepageText` message. Here is an example of a `HomepageText.result`: - -``` -Howdy Ada! - -Liked Songs: -* Sunny by Boney M. -* J'irai où tu iras by Céline Dion & Jean-Jacques Goldman -* Hold the line by TOTO - -Activity Feed: -* Bob is listening to Straight Edge by Minor Threat -* Donald is listening to Désenchantée by Mylène Farmer -* Carol is listening to Breakfast in America by Supertramp -``` - -More precisely, it should contains the following lines in order: - -1. `Howdy $name!`, where `$name` is the name of the recipient user. -2. A blank line -3. `Liked Songs:` -4. Zero or more lines listing the user's liked songs. Each of these lines should be of the form `"* ${song.title} by ${song.artist}`, where `${song.title}` is the title of the song and `${song.artist}` its artist. -5. A blank line -6. Zero or more lines listing the user activity feed items. Each of these lines should be of the form `* ${user.name} is listening to ${song.title} by ${song.artist}`, where `${user.name}` is the name of the user listening, `${song.title}` is the title of the song and `${song.artist}` its artist. - -In order to fetch the songs information (titles and artists), you should use the `songStore` actor passed as an argument to `User`. See the enums in the `SongsStore` companion object to learn how to interact with the song store. - -__Hint 1:__ to construct the result, you might find useful to use [`f-strings`](https://docs.scala-lang.org/overviews/core/string-interpolation.html#the-f-interpolator) and the [`List.mkString`](https://www.scala-lang.org/api/2.13.3/scala/collection/immutable/List.html#mkString(sep:String):String) method. Here is an example of how to use them: - -```scala -val fruits = List("Banana", "Apple", "Kiwi") -val result = f"""Fruits: -${fruits.map(fruit => f"* ${fruit}").mkString("\n")}""" - -assert(result == """Fruits: -* Banana -* Apple -* Kiwi""") -``` - -__Hint 2:__ if you need to send the result of a future to an actor, you should use the `pipeTo` method as described in the lectures and [here](https://doc.akka.io/docs/akka/2.5/futures.html#use-the-pipe-pattern). diff --git a/final/instructions/spotify.jpg b/final/instructions/spotify.jpg deleted file mode 100644 index 79f91ad367a09ab3348ff0c167eaa9ddbdba8f37..0000000000000000000000000000000000000000 Binary files a/final/instructions/spotify.jpg and /dev/null differ diff --git a/grading-gitlab-ci.yml b/grading-gitlab-ci.yml deleted file mode 100644 index f8fdce6e0f2bbada6afd6a7fb5d5b41da2a56f9d..0000000000000000000000000000000000000000 --- a/grading-gitlab-ci.yml +++ /dev/null @@ -1,52 +0,0 @@ -# This CI config file is not used in this repository but instead referenced -# from each student project (https://gitlab.epfl.ch/help/ci/pipelines/settings#custom-ci-configuration-path) -# and used to grade them. - -workflow: - rules: - # Don't run the CI on commit messages contain "[no-ci]", used to deploy - # assignments without overloading the CI. - - if: $CI_COMMIT_MESSAGE !~ /\[no-ci\]/ - -stages: - - build - - grade - -variables: - OUTPUT_DIR: "-" - -compile: - stage: build - timeout: 10m - image: ${DOCKER_REPO}/compile - tags: - - cs210 - except: - - tags - - master - script: - - sbt packageSubmission - # Output of this job that needs to be stored to be reused in the grade job below - artifacts: - expire_in: 20m - paths: - - submission.jar - -grade: - stage: grade - timeout: 10m - except: - - tags - - master - tags: - - cs210 - image: - name: ${DOCKER_REPO}/grader-${CI_COMMIT_BRANCH} - entrypoint: [""] - allow_failure: true - before_script: - - mkdir -p /shared/submission/ - - cp submission.jar /shared/submission/submission.jar - script: - - cd /grader - - env -i bash --noprofile --norc -c "/grader/grade ch.epfl.lamp.grading.CourseraGrading -" diff --git a/labs/example-lab.md b/labs/example-lab.md deleted file mode 100644 index 12a825bdfaabf32808cafa2b5840742dc7300342..0000000000000000000000000000000000000000 --- a/labs/example-lab.md +++ /dev/null @@ -1,298 +0,0 @@ -# Example lab - -The goal of this lab is to familiarize yourself with the infrastructure and tools used in this class. Even though the grade in this lab won't influence your grade for the course, it is important that you work through this lab carefully. - -## Part 1: Obtaining the Project Files - -First, make sure you've followed the [Tools Setup](tools-setup.md) page. - -**At this point, we strongly encourage you to take the time to read at least the first three chapters of the [Git Book](https://git-scm.com/book/en/v2). If you just copy-paste the commands we give you without understanding them, it's likely that you'll make a mistake somewhere and waste time. Git can be a huge productivity enhancer when used correctly, so it's definitely worth the investment!** - -We'll starting by cloning the repository containing all our lab (make -sure to replace `GASPAR` with your EPFL username (the one with letters, not the -one with number) in the following command). - -```shell -git clone -b example git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-example -``` - -**If this command fails, make sure you've [logged into -gitlab](https://gitlab.epfl.ch/users/sign_in) and filled [this form](https://forms.gle/N6F3Q3jZm71AASby9), -then wait a few minutes. -If it still doesn't work it's likely that you didn't correctly upload your ssh -key to gitlab, look at the last part of the [Tools Setup](tools-setup.md) page again.** - -```shell -cd cs206-example -``` - -Now that we've obtained the project, let's take a look at its structure: - -```shell -. -├── build.sbt -├── project -│ ├── ... -└── src - ├── main - │ └── scala - │ └── example - │ └── Lists.scala - └── test - └── scala - └── example - └── ListsSuite.scala -``` - -- All the files ending with `.sbt` or in the `project/` directory are build tool configuration files: you don't need to modify them or look at them for any of the labs -- The project sources are in `src/main/scala/` -- The sources of the unit tests are in `src/test/scala/`. You will need to make all the tests pass to complete the labs, and you should write additional tests to check for cases that our tests do not cover. - -## Part 2: Using sbt - -Start sbt by running: -```shell -sbt -``` - -Once it's finished starting (this may take a while), you'll be able to enter sbt -commands. You can compile your project using `compile` and run the tests with -`test` (this automatically compiles your code if needed to). Note that if -compilation fails, no tests will be run. The first time you'll run `test` in an -lab you should see many errors: that's normal, your job is to make the -tests pass! But first, let's look at a failed test in detail: - - - -This tells us several things: - -- There's a test named `sum of a few numbers (10pts)` in the class `ListsSuite` in the package `example` -- The test failed (that's why it's in red and starts with `==> X`) with an exception: `NotImplementedError`. -- This exception was thrown from the method `???` in `scala.Predef` in the file - `Predef.scala`, this file is not part of our project (that's why it's in - grey), to find the actual error in our code we have to look at where this - method was called from. -- This method was called from method `max` in `example.Lists` in the file - `Lists.scala` at line 40, this is where the bug is! -- It's also important to see where in our test this was called from, here - it's line 102 of `ListsSuite.scala`. - -Time to go fix that bug! The next section will show you how to do that using the IDE. - -## Part 3: Using the IDE - -### Setup - -Let's upgrade the IDE support first, close VSCode if it's open and run: - -```shell -code --force --install-extension scalameta.metals -``` - -### Startup - -To start Code, run the following in the project directory (the same directory where you -previously ran `sbt`), it's important to run Code in the correct directory or -it won't be able to import your project: - -```shell -code . -``` - -(In this command the `.` is important, it's how we tell Code to run in the -current directory) - -(if you see an error `Expected ';'` it means you're inside sbt, open a new -terminal in the same directory) - -The first time the IDE starts, it will take some time to download more -components, eventually it will ask you to import the build, please click "Import -build": - - - -You'll need to wait a bit for the import to finish, if an error appears try -closing and restarting Code in the same way we started it above. -### Usage - -It's now time to dig in! Earlier we talked about a failing test, the stack trace -told us that it was failing on line 102 of the file `ListsSuite.scala`, so let's open that file: - - - -Here's the source code of the test: - - - -The first line gives a name to the test, the second line runs -`sum(List(1, 2, 0))` and tests that it equals 3, but in our case we never got to -this point because an exception was thrown, recall that the second line -of the stack trace was: - -```scala -at example.Lists$.sum(Lists.scala:25) -``` - -This tells us that the crash happened when calling `sum`, we can hover with our mouse over the call to `sum` in the test method to get more information on it: - - - -**If hovering doesn't show this see the [Troubleshooting](#troubleshooting) section.** - -The hover is split into two parts: the first part is: -```scala -def sum(xs: List[Int]): Int -``` -This means that `sum` is a method that takes a `List` of `Int` as argument and -returns an `Int`. The second part is the documentation of `sum`. We can jump to -the definition of sum by `Ctrl+click` (`Cmd+click` on Mac) or by `right click -> -Go to Definition`. Once there we see: - - - -Now we know why the test failed: `sum` calls `???`, which is a method defined in -the Scala standard library that simply crashes your program: whenever you see it -in a lab it means that this is something you need to replace by your own -implementation. - -Once you've implemented this method, you can run `test` from sbt again to see if -the test passed, if you want to run a single test instead of all tests you can -use `testOnly` instead and specify part of the name of the test: -```scala -testOnly -- "--tests=.*max of a few.*" -``` - -You now know enough to be able to work with the IDE, here are some additional tips: - -- When you press `Enter` to make a new line, the IDE will automatically indent the - line if needed (for example, if the last word on the previous line was - `then`), however it will never unindent code for you (for example, when - writing `else`). You can indent code manually by pressing `Tab` and - unindent it by pressing `Backspace` or `Shift + Tab`. -- When working on an lab, you are free to create as many methods, classes and objects as you want. **But you shouldn't change the name of existing methods, classes and objects, because that may break the automated grading system, this is important!**. -- You can see a list of all warnings and errors reported by the compiler by clicking on  at the bottom left of Code. -- The IDE can show you on hover the documentation of classes, defs and vals defined in the current project but support for external project is currently missing. To compensate for this, you can consult the documentation online: - - The documentation for the Scala standard library is at [https://www.scala-lang.org/files/archive/api/2.13.3/](https://www.scala-lang.org/files/archive/api/2.13.3/) - - The documentation for the Java standard library is at [https://docs.oracle.com/en/java/javase/15/docs/api/index.html](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) -- You can customize Code as much as you want, including installing additional extensions, but please avoid installing other Scala-related extensions: they may conflict with the one we use for this course. -- While working on your lab, you will regularly want to go back to the sbt console to run the tests. You could simply run the command `test` every time, but you can take advantage of the watch mode instead: if a command is prefixed by `~`, sbt will watch the source directory for changes and re-run the command every time a file is saved. So a possible workflow is: - - 1. Start the IDE - 2. Start sbt in the terminal (protip: you can start a terminal inside Code from the - menu: `Terminal -> New Terminal`) - 3. Inside sbt, run `~test` - 4. Work in the IDE, and check the output of the sbt console from time to time - -## Part 4: Running your code - -Writing code and running tests is nice, but sometimes more direct feedback is useful, like when you want to experiment with Scala, or try out some methods that you implemented. You can do this using the Scala REPL (Read/Eval/Print Loop) or with a worksheet. - -### The REPL -After having started sbt, you can start the REPL by typing `console`, you will see the following prompt: -```scala -scala> -``` -At this point you can write any Scala expression you want, for example: -```scala -scala> val l = List(3,7,2) -val l: List[Int] = List(3, 7, 2) -``` - -(If you write an expression without wrapping it in a `val` or a `def`, the REPL will give it a name for you, starting with `res`) - -```scala -scala> l.isEmpty -val res0: Boolean = false - -scala> println(res0) -false - -scala> l.tail.head -res1: Int = 7 - -scala> List().isEmpty -res2: Boolean = true -``` - -The classes of the lab are available inside the REPL, so you can for instance import all the methods from `object Lists` and start using `max`: - -```scala -scala> import example.Lists._ -import example.Lists._ - -scala> max(List(1,3,2)) -res1: Int = 3 -``` - -You can enter a multiline expression in the REPL by using `Alt+Enter` instead of `Enter`: - -```scala -scala> if 1 == 1 then - | "a" - | else - | "b" -val res0: String = a -``` - -(on macOS, first go to `Terminal -> Preference -> Profiles -> Keyboard` and then -select `Use Option as Meta key`, then `Option+Enter` will work for multiline -expressions.) - -In order to exit the Scala REPL and go back to sbt, type `Ctrl+D`. - -### The worksheet mode -A *worksheet* is a file where every line of code written in the IDE is executed and its output displayed as a comment. - -#### Creating a worksheet -Any file that ends in `.worksheet.sc` is considered to be a worksheet by the IDE. Once Code is launched in a project, all you have to do is create a new file and save it (`Ctrl+N, Ctrl+S`) using any name as long as it ends in `.worksheet.sc`. - -#### Using the worksheet mode - -Inside this file, you can type any line of code you would type in the REPL. The -worksheet will be automatically run when the code is saved and auto-save is -enabled by default. Each line of code will be executed one by one and its output -will be shown in green on the right. - -## Part 5: Submitting your Solution - -[Click here to learn how to submit your lab.](grading-and-submission.md) - -# Troubleshooting - -## sbt fails to start - -If you see any kind of error when sbt starts that prevents you from using it, -try cleaning the project cache by running: -```shell -git clean -Xdf -``` -Then restarting `sbt`, if this still doesn't work, try deleting the global sbt -cache: -```shell -rm -r ~/.sbt -``` - -## IDE features like type-on-hover or go-to-definition do not work - -It's likely that the build wasn't imported, we can import it manually: - -Click on the "m" logo in the left bar (where the red arrow is in the screenshot below): - - - -In the sidebar that appears, click on "Import build", then wait a bit: - - - -If things still don't work, try restarting Code (launch it in the same way you -started it before, using `code .` from the project directory). If you're still -having issues, try clicking on "Clean compile workspace" from the same -sidebar. - -## Warning about Bloop installed version - -If you get a warning like this: - - - -Please click the first button "Turn off old server". diff --git a/labs/grading-and-submission.md b/labs/grading-and-submission.md deleted file mode 100644 index c7dbcc9f2237e2f08578b857bb0e0ba52348e23e..0000000000000000000000000000000000000000 --- a/labs/grading-and-submission.md +++ /dev/null @@ -1,106 +0,0 @@ -# Grading and submission - -## Local tests and grading - -Each lab is shipped with two sets of tests: - * The tests defined under `src/test/scala`, these are usually incomplete: we - strongly encourage you to write additional tests to exercise every aspect of - your code. You can run these tests from `sbt` using the following command: - ```shell - test - ``` - * The **grading tests**, that we use to grade your labs, these are - provided as a "black box": you can run them but are not allowed to see their - content, to encourage you to write your own tests. You can run them from - `sbt` using the following command: - ```shell - Grading/test - ``` - - Your grade is determined by the number of these tests that pass, see the - next section to see how to actually get a grade. - -(remember that you can always put `~` before an sbt command to automatically -re-run it when you save a file) - -## Committing and pushing your code - -**You need to push your code to gitlab before the deadline for the lab to -receive a grade. If you forget, your grade will be zero.** - -If you've read the first few chapters of [Git -book](https://git-scm.com/book/en/v2) as recommended, you must already be -familiar with committing and pushing, but let's go over the basics once again: - -At any point while working on an lab, you can see what changes you -haven't committed by writing: -```shell -git status -``` - -(If you get the error `Not a valid command: git`, it means you're inside sbt, -you can't run git from sbt itself, you need to open another terminal in the same -directory) - -This will display the list of files you have modified since the last commit, to -see the exact changes you made, run: -```shell -git diff -``` - -To save these changes in a commit, run: (replace `"My message"` by a message -describing the changes since the last commit, see [How to Write a Git Commit -Message](https://chris.beams.io/posts/git-commit/) for some tips on writing -good commit messages) -```shell -git commit -am "My message" -``` - -(It's good practice to commit your code regularly to document your changes) - -You can then synchronize your local git repository with the gitlab server by -first running: -```shell - git pull --no-rebase -``` - -This will merge in your local repository any change we made to the lab -(we only change labs to fix critical bugs found after it's been released, -so most of the time this will not do anything). - -Finally, you can push your changes to gitlab: -```shell -git push -``` - -Note that there are also graphical user interfaces to interact with git, for -example [VSCode has built-in git -support](https://code.visualstudio.com/docs/editor/versioncontrol#_git-support). - -Once you've pushed your code, you can see the result online by going to -`gitlab.epfl.ch/lamp/student-repositories-s22/cs206-GASPAR/pipelines` where -`GASPAR` is your username (you can also access this page from the main page of -your repository by clicking on the rocket icon on the left side of the gitlab -interface, then clicking on "Pipelines"). - - - -The grading pipeline contains two steps: - * *compile*: your code does not compile for grading if the job fail. - * *grade*: the job results in a warning if you do not get the maximum grade - (10.00/10.00) - -If a job is marked "pending", it means there are other students running jobs at -the same time and you'll have to wait a bit for your job to run. - -You can click on the `grade` job to see its output: - - - - - -Your grade is given on the line that starts with `Your overall score for this -lab is` - -**If you push to gitlab multiple times, your final grade will be based on the -last commit you pushed before the deadline.** diff --git a/labs/images/bloop-update.png b/labs/images/bloop-update.png deleted file mode 100644 index 788bc5f8a71c9d1f9f71045a0749562420cc6f41..0000000000000000000000000000000000000000 Binary files a/labs/images/bloop-update.png and /dev/null differ diff --git a/labs/images/clone-url.png b/labs/images/clone-url.png deleted file mode 100644 index 784cec1aecafc709da76a3f23bebadf7cfdc180a..0000000000000000000000000000000000000000 Binary files a/labs/images/clone-url.png and /dev/null differ diff --git a/labs/images/gitlab-public-ssh-key.png b/labs/images/gitlab-public-ssh-key.png deleted file mode 100644 index f57459d9d7862d4a924a327b629583d01725932f..0000000000000000000000000000000000000000 Binary files a/labs/images/gitlab-public-ssh-key.png and /dev/null differ diff --git a/labs/images/gitlab-settings.png b/labs/images/gitlab-settings.png deleted file mode 100644 index 1f5363204a2e91c337bb8296cc8c7efd158d9304..0000000000000000000000000000000000000000 Binary files a/labs/images/gitlab-settings.png and /dev/null differ diff --git a/labs/images/hover.png b/labs/images/hover.png deleted file mode 100644 index 6065791252eb55880f76b370ccc572a3c24c5a1c..0000000000000000000000000000000000000000 Binary files a/labs/images/hover.png and /dev/null differ diff --git a/labs/images/import-build.png b/labs/images/import-build.png deleted file mode 100644 index 509db479f515b1ed4133de36cc0b3da2a65c2985..0000000000000000000000000000000000000000 Binary files a/labs/images/import-build.png and /dev/null differ diff --git a/labs/images/menu-metals.png b/labs/images/menu-metals.png deleted file mode 100644 index 869dfa1f1be431d05fca5d09a97d1ad7e76b85e9..0000000000000000000000000000000000000000 Binary files a/labs/images/menu-metals.png and /dev/null differ diff --git a/labs/images/metals-import.png b/labs/images/metals-import.png deleted file mode 100644 index 57f5c5e4af4139202d440c3fcb59c3d7665aae4a..0000000000000000000000000000000000000000 Binary files a/labs/images/metals-import.png and /dev/null differ diff --git a/labs/images/open-test.png b/labs/images/open-test.png deleted file mode 100644 index b397b1810ff800961b051506ec5f4d5b6de75b5b..0000000000000000000000000000000000000000 Binary files a/labs/images/open-test.png and /dev/null differ diff --git a/labs/images/pipeline-details.png b/labs/images/pipeline-details.png deleted file mode 100644 index 426346c5adbc56e96f48e572c35018fd66456371..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-details.png and /dev/null differ diff --git a/labs/images/pipeline-logs.png b/labs/images/pipeline-logs.png deleted file mode 100644 index 607626e390391db912455cd95748cb07459afde2..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-logs.png and /dev/null differ diff --git a/labs/images/pipeline-tab.png b/labs/images/pipeline-tab.png deleted file mode 100644 index b2756a91a19ceb5972c00295fb8796958d1a91ae..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-tab.png and /dev/null differ diff --git a/labs/images/sbt-test-error.png b/labs/images/sbt-test-error.png deleted file mode 100644 index 3e0856eeee0a8276df224e2d30820f41addd12c1..0000000000000000000000000000000000000000 Binary files a/labs/images/sbt-test-error.png and /dev/null differ diff --git a/labs/images/sum-def.png b/labs/images/sum-def.png deleted file mode 100644 index 43d763dbf432bf203e85b1a9146b74092998a2b5..0000000000000000000000000000000000000000 Binary files a/labs/images/sum-def.png and /dev/null differ diff --git a/labs/images/syntax-error-bug.png b/labs/images/syntax-error-bug.png deleted file mode 100644 index a2a53b294e0b8c848e5a524521268c74436b322d..0000000000000000000000000000000000000000 Binary files a/labs/images/syntax-error-bug.png and /dev/null differ diff --git a/labs/images/test-source.png b/labs/images/test-source.png deleted file mode 100644 index dbd3f7e3a9b2629b196603664a17f07cdbdd2a7f..0000000000000000000000000000000000000000 Binary files a/labs/images/test-source.png and /dev/null differ diff --git a/labs/images/warnings-errors.png b/labs/images/warnings-errors.png deleted file mode 100644 index be5b9d6ff528c1e1b51523217078a54b48f10399..0000000000000000000000000000000000000000 Binary files a/labs/images/warnings-errors.png and /dev/null differ diff --git a/labs/lab1-parallel-box-blur-filter/README.md b/labs/lab1-parallel-box-blur-filter/README.md deleted file mode 100755 index 48da29b466ed264741019ecc6ecb61b4c37ce0f9..0000000000000000000000000000000000000000 --- a/labs/lab1-parallel-box-blur-filter/README.md +++ /dev/null @@ -1,318 +0,0 @@ -# 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-s22/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: - - - -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. - - - -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: - - - -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: - - - -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.* diff --git a/labs/lab1-parallel-box-blur-filter/avg.svg b/labs/lab1-parallel-box-blur-filter/avg.svg deleted file mode 100755 index dd2eea9a1e5112c9fc0237950692a7ddca23b650..0000000000000000000000000000000000000000 --- a/labs/lab1-parallel-box-blur-filter/avg.svg +++ /dev/null @@ -1,360 +0,0 @@ -<?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> diff --git a/labs/lab1-parallel-box-blur-filter/horiz.svg b/labs/lab1-parallel-box-blur-filter/horiz.svg deleted file mode 100755 index b20844e771db0fac5f74a02ce168f16957d57db5..0000000000000000000000000000000000000000 --- a/labs/lab1-parallel-box-blur-filter/horiz.svg +++ /dev/null @@ -1,360 +0,0 @@ -<?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> diff --git a/labs/lab1-parallel-box-blur-filter/horizontal.png b/labs/lab1-parallel-box-blur-filter/horizontal.png deleted file mode 100755 index cc52fe74986a3bbebda0200ec89f5f9202ec0a05..0000000000000000000000000000000000000000 Binary files a/labs/lab1-parallel-box-blur-filter/horizontal.png and /dev/null differ diff --git a/labs/lab1-parallel-box-blur-filter/kernel.png b/labs/lab1-parallel-box-blur-filter/kernel.png deleted file mode 100755 index 06aeca6c29596c6104302991be09c442a9dc78be..0000000000000000000000000000000000000000 Binary files a/labs/lab1-parallel-box-blur-filter/kernel.png and /dev/null differ diff --git a/labs/lab1-parallel-box-blur-filter/mapping.png b/labs/lab1-parallel-box-blur-filter/mapping.png deleted file mode 100755 index c8ba9ef5d9a96550eb0a1eeba45fbcad0423b469..0000000000000000000000000000000000000000 Binary files a/labs/lab1-parallel-box-blur-filter/mapping.png and /dev/null differ diff --git a/labs/lab1-parallel-box-blur-filter/mapping.svg b/labs/lab1-parallel-box-blur-filter/mapping.svg deleted file mode 100755 index c36c621eff29c31af15bbe02964d146bf4de9e44..0000000000000000000000000000000000000000 --- a/labs/lab1-parallel-box-blur-filter/mapping.svg +++ /dev/null @@ -1,735 +0,0 @@ -<?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> diff --git a/labs/lab1-parallel-box-blur-filter/vert.svg b/labs/lab1-parallel-box-blur-filter/vert.svg deleted file mode 100755 index d20644e4b792f9e5caa0b676c31a6aa938360450..0000000000000000000000000000000000000000 --- a/labs/lab1-parallel-box-blur-filter/vert.svg +++ /dev/null @@ -1,462 +0,0 @@ -<?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> diff --git a/labs/lab1-parallel-box-blur-filter/vertical.png b/labs/lab1-parallel-box-blur-filter/vertical.png deleted file mode 100755 index 02c71ab3fb1bb6783dd0e756c85a855d7353f36f..0000000000000000000000000000000000000000 Binary files a/labs/lab1-parallel-box-blur-filter/vertical.png and /dev/null differ diff --git a/labs/lab2-reductions-and-prefix-sums/README.md b/labs/lab2-reductions-and-prefix-sums/README.md deleted file mode 100644 index c3099ea6be82b692fec6fac436445b5ab7fe4588..0000000000000000000000000000000000000000 --- a/labs/lab2-reductions-and-prefix-sums/README.md +++ /dev/null @@ -1,355 +0,0 @@ -# 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-s22/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 deleted file mode 100644 index bd478938260a921b527b14d622e57d7f951c8da3..0000000000000000000000000000000000000000 --- a/labs/lab2-reductions-and-prefix-sums/angle-example-2.svg +++ /dev/null @@ -1,209 +0,0 @@ -<?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 deleted file mode 100644 index fd674128904de49c6b165b094b478f33c029f64b..0000000000000000000000000000000000000000 --- a/labs/lab2-reductions-and-prefix-sums/angle-example.svg +++ /dev/null @@ -1,154 +0,0 @@ -<?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 deleted file mode 100644 index 50a8cc00497fa82cbb7442ac40ddd56b88dc9885..0000000000000000000000000000000000000000 Binary files a/labs/lab2-reductions-and-prefix-sums/angle.png and /dev/null differ diff --git a/labs/lab2-reductions-and-prefix-sums/angle2.png b/labs/lab2-reductions-and-prefix-sums/angle2.png deleted file mode 100644 index d5b4fccface66a660bcee7539458198423fb674e..0000000000000000000000000000000000000000 Binary files a/labs/lab2-reductions-and-prefix-sums/angle2.png and /dev/null differ diff --git a/labs/lab2-reductions-and-prefix-sums/terrain.png b/labs/lab2-reductions-and-prefix-sums/terrain.png deleted file mode 100644 index 11ba1b6f55b18bdd7d93e73c3e751739eaf1be32..0000000000000000000000000000000000000000 Binary files a/labs/lab2-reductions-and-prefix-sums/terrain.png and /dev/null differ diff --git a/labs/lab2-reductions-and-prefix-sums/terrain.svg b/labs/lab2-reductions-and-prefix-sums/terrain.svg deleted file mode 100644 index d9073e066c7e53114119200db0a88d9084909c11..0000000000000000000000000000000000000000 --- a/labs/lab2-reductions-and-prefix-sums/terrain.svg +++ /dev/null @@ -1,112 +0,0 @@ -<?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 deleted file mode 100644 index 9a26107e64f77f3a6d217f5ea80e0cffdb8127d8..0000000000000000000000000000000000000000 Binary files a/labs/lab2-reductions-and-prefix-sums/visibility.png and /dev/null differ diff --git a/labs/lab2-reductions-and-prefix-sums/visibility.svg b/labs/lab2-reductions-and-prefix-sums/visibility.svg deleted file mode 100644 index e4f1882336cea5d065a7d1f96c00e5de991a77ae..0000000000000000000000000000000000000000 --- a/labs/lab2-reductions-and-prefix-sums/visibility.svg +++ /dev/null @@ -1,131 +0,0 @@ -<?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> diff --git a/labs/lab3-k-means/README.md b/labs/lab3-k-means/README.md deleted file mode 100644 index 8ea1885845997922c2a8dd14bd1b154a87080ce4..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/README.md +++ /dev/null @@ -1,265 +0,0 @@ -# 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-s22/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: - - - -As a human, you can visually distinguish the three clusters of points in the -image: - - - -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: - - - -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: - - - -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: - - - -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: - - - -And then we update the means again: - - - -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: - - - -And this is the indexed color (32 colors) version of it: - - - -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! diff --git a/labs/lab3-k-means/clusters.png b/labs/lab3-k-means/clusters.png deleted file mode 100644 index 1f3bdf3729d54356d8040e2d1e561da35c980ece..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/clusters.png and /dev/null differ diff --git a/labs/lab3-k-means/clusters.svg b/labs/lab3-k-means/clusters.svg deleted file mode 100644 index c615e29752918ff7d747daa4706fb5f9a7e5ec8b..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/clusters.svg +++ /dev/null @@ -1,290 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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:xlink="http://www.w3.org/1999/xlink" - 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\kmeans\clusters.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="clusters.svg"> - <defs - id="defs4"> - <linearGradient - inkscape:collect="always" - id="linearGradient7516"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7518" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop7520" /> - </linearGradient> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7522" - cx="208.57138" - cy="248.07649" - fx="208.57138" - fy="248.07649" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(19.192898,14.142136)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7524" - cx="204.28568" - cy="378.07651" - fx="204.28568" - fy="378.07651" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-16.162441,-5.0507627)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7526" - cx="171.42856" - cy="326.64792" - fx="171.42856" - fy="326.64792" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(67.680221,14.142136)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7528" - cx="128.57144" - cy="382.36221" - fx="128.57144" - fy="382.36221" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(173.74624,-79.802054)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7530" - cx="98.571434" - cy="316.64792" - fx="98.571434" - fy="316.64792" - r="11.25" - gradientUnits="userSpaceOnUse" /> - </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="407.41238" - inkscape:cy="632.82609" - 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" /> - </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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:url(#radialGradient7530);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:url(#radialGradient7528);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:url(#radialGradient7526);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:url(#radialGradient7524);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:url(#radialGradient7522);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <ellipse - style="fill:none;fill-opacity:0.29677417;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:7.5,2.5;stroke-dashoffset:0;stroke-opacity:1" - id="path7554" - cx="210.61681" - cy="311.41531" - rx="177.28177" - ry="122.73354" /> - <ellipse - ry="122.91036" - rx="130.4865" - cy="191.20717" - cx="534.37073" - id="ellipse7556" - style="fill:none;fill-opacity:0.29677417;stroke:#000000;stroke-width:2.14636397;stroke-miterlimit:4;stroke-dasharray:6.43909181, 2.14636394;stroke-dashoffset:0;stroke-opacity:1" /> - <ellipse - style="fill:none;fill-opacity:0.29677417;stroke:#000000;stroke-width:1.89697337;stroke-miterlimit:4;stroke-dasharray:5.69092025, 1.89697342;stroke-dashoffset:0;stroke-opacity:1" - id="ellipse7558" - cx="520.73364" - cy="473.03973" - rx="101.82184" - ry="123.03506" /> - </g> -</svg> diff --git a/labs/lab3-k-means/points.png b/labs/lab3-k-means/points.png deleted file mode 100644 index 5584dba6d2bae31eb6e5627089acaed405fbf130..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/points.png and /dev/null differ diff --git a/labs/lab3-k-means/points.svg b/labs/lab3-k-means/points.svg deleted file mode 100644 index f9ae8e6c80581c5c5055979e9e0af77531036843..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/points.svg +++ /dev/null @@ -1,270 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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:xlink="http://www.w3.org/1999/xlink" - 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\kmeans\points.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="points.svg"> - <defs - id="defs4"> - <linearGradient - inkscape:collect="always" - id="linearGradient7516"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7518" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop7520" /> - </linearGradient> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7522" - cx="208.57138" - cy="248.07649" - fx="208.57138" - fy="248.07649" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(19.192898,14.142136)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7524" - cx="204.28568" - cy="378.07651" - fx="204.28568" - fy="378.07651" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-16.162441,-5.0507627)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7526" - cx="171.42856" - cy="326.64792" - fx="171.42856" - fy="326.64792" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(67.680221,14.142136)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7528" - cx="128.57144" - cy="382.36221" - fx="128.57144" - fy="382.36221" - r="11.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(173.74624,-79.802054)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7516" - id="radialGradient7530" - cx="98.571434" - cy="316.64792" - fx="98.571434" - fy="316.64792" - r="11.25" - gradientUnits="userSpaceOnUse" /> - </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="407.41238" - inkscape:cy="632.82609" - 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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:url(#radialGradient7530);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:url(#radialGradient7528);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:url(#radialGradient7526);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:url(#radialGradient7524);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:url(#radialGradient7522);fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - </g> -</svg> diff --git a/labs/lab3-k-means/start.png b/labs/lab3-k-means/start.png deleted file mode 100644 index 2201ffd533d0848deb569862a90a871d9e9f6d8c..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/start.png and /dev/null differ diff --git a/labs/lab3-k-means/step0.png b/labs/lab3-k-means/step0.png deleted file mode 100644 index 97668674d5d95b560abcd018225499e141747edc..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/step0.png and /dev/null differ diff --git a/labs/lab3-k-means/step0.svg b/labs/lab3-k-means/step0.svg deleted file mode 100644 index c73a7130473f6498f7405a223fcce1edd3995891..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/step0.svg +++ /dev/null @@ -1,239 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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\kmeans\clusters.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="step0.svg"> - <defs - id="defs4"> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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="407.41238" - inkscape:cy="632.82609" - 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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875067px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="196.82574" - y="608.31287" - id="text7568" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7570" - x="196.82574" - y="608.31287">X</tspan></text> - <text - transform="scale(1.1239557,0.8897148)" - sodipodi:linespacing="125%" - id="text7572" - y="424.38351" - x="521.27362" - style="font-style:normal;font-weight:bold;font-size:35.58875047px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - xml:space="preserve"><tspan - y="424.38351" - x="521.27362" - id="tspan7574" - sodipodi:role="line">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875084px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="321.75165" - y="257.48459" - id="text7576" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7578" - x="321.75165" - y="257.48459">X</tspan></text> - </g> -</svg> diff --git a/labs/lab3-k-means/step1.png b/labs/lab3-k-means/step1.png deleted file mode 100644 index 8ce72d8c0c36d2aa84a222e570cdd9582f4dfc8a..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/step1.png and /dev/null differ diff --git a/labs/lab3-k-means/step1.svg b/labs/lab3-k-means/step1.svg deleted file mode 100644 index e210b991b67e1f4a226ff3769bd30339de18b0b7..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/step1.svg +++ /dev/null @@ -1,257 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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\kmeans\clusters.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="step1.svg"> - <defs - id="defs4"> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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="407.41238" - inkscape:cy="632.82609" - 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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875067px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="196.82574" - y="608.31287" - id="text7568" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7570" - x="196.82574" - y="608.31287">X</tspan></text> - <text - transform="scale(1.1239557,0.8897148)" - sodipodi:linespacing="125%" - id="text7572" - y="424.38351" - x="521.27362" - style="font-style:normal;font-weight:bold;font-size:35.58875047px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - xml:space="preserve"><tspan - y="424.38351" - x="521.27362" - id="tspan7574" - sodipodi:role="line">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875084px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="321.75165" - y="257.48459" - id="text7576" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7578" - x="321.75165" - y="257.48459">X</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 29.294424,236.15895 387.89857,389.70213" - id="path7612" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 386.88842,387.68183 535.38085,689.71744" - id="path7614" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 386.88843,389.70213 622.25396,144.23507" - id="path7616" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/labs/lab3-k-means/step2.png b/labs/lab3-k-means/step2.png deleted file mode 100644 index 6cdc2c8e9732a38680b5642ac817b8539815b06f..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/step2.png and /dev/null differ diff --git a/labs/lab3-k-means/step2.svg b/labs/lab3-k-means/step2.svg deleted file mode 100644 index db6e99dac1722683bc4c5f76439fbbdbe8088027..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/step2.svg +++ /dev/null @@ -1,408 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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:xlink="http://www.w3.org/1999/xlink" - 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\kmeans\clusters.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="step2.svg"> - <defs - id="defs4"> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker10709" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path10711" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker9251" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path9253" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4153" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow2Lend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4165" - style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " - transform="scale(1.1) rotate(180) translate(1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker8251" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path8253" - 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> - <linearGradient - inkscape:collect="always" - id="linearGradient8215"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop8217" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop8219" /> - </linearGradient> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8215" - id="linearGradient8221" - x1="119.05175" - y1="385.33261" - x2="145.39577" - y2="385.33261" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.67277217" - inkscape:cx="372.04724" - inkscape:cy="526.1811" - 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 /> - </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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875067px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="196.82574" - y="608.31287" - id="text7568" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7570" - x="196.82574" - y="608.31287">X</tspan></text> - <text - transform="scale(1.1239557,0.8897148)" - sodipodi:linespacing="125%" - id="text7572" - y="424.38351" - x="521.27362" - style="font-style:normal;font-weight:bold;font-size:35.58875047px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - xml:space="preserve"><tspan - y="424.38351" - x="521.27362" - id="tspan7574" - sodipodi:role="line">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:bold;font-size:35.58875084px;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;-inkscape-font-specification:'sans-serif, Bold';font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;" - x="321.75165" - y="257.48459" - id="text7576" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - sodipodi:role="line" - id="tspan7578" - x="321.75165" - y="257.48459">X</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 29.294424,236.15895 387.89857,389.70213" - id="path7612" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 386.88842,387.68183 535.38085,689.71744" - id="path7614" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:7.5,7.5;stroke-dashoffset:0" - d="M 386.88843,389.70213 622.25396,144.23507" - id="path7616" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8211" - y="385.78098" - x="145.59712" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="385.78098" - x="145.59712" - id="tspan8213" - sodipodi:role="line" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-opacity:1">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - x="363.9928" - y="221.1528" - id="text8235" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-opacity:1" - sodipodi:role="line" - id="tspan8237" - x="363.9928" - y="221.1528">X</tspan></text> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8239" - y="556.086" - x="465.5513" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="556.086" - x="465.5513" - id="tspan8241" - sodipodi:role="line" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-opacity:1">X</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:12, 6;stroke-opacity:1;marker-end:url(#Arrow1Mend);stroke-dashoffset:0" - d="M 188.36461,528.28085 C 127.91334,484.20672 112.42805,448.37274 158.00235,365.76166" - id="path8243" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path9249" - d="M 377.1358,198.30287 C 333.03479,124.501 411.1919,113.9356 415.14736,162.1266" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:12, 6;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker9251)" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path10707" - d="m 617.93054,393.01961 c 22.78642,45.10911 13.24668,80.62172 -58.60362,88.68026" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:12, 6;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker10709)" /> - </g> -</svg> diff --git a/labs/lab3-k-means/step3.png b/labs/lab3-k-means/step3.png deleted file mode 100644 index a0f1e2f4e887a1b4aa6b7d785bdfa7334171de4e..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/step3.png and /dev/null differ diff --git a/labs/lab3-k-means/step3.svg b/labs/lab3-k-means/step3.svg deleted file mode 100644 index b4a9fec9e230fa8cf73bc23b12e26d9b9541465b..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/step3.svg +++ /dev/null @@ -1,353 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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:xlink="http://www.w3.org/1999/xlink" - 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\kmeans\step3.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="step3.svg"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4153" - 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:1.0pt;" - transform="scale(0.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker10709" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path10711" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker9251" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path9253" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow2Lend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4165" - style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " - transform="scale(1.1) rotate(180) translate(1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker8251" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path8253" - 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> - <linearGradient - inkscape:collect="always" - id="linearGradient8215"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop8217" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop8219" /> - </linearGradient> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8215" - id="linearGradient8221" - x1="119.05175" - y1="385.33261" - x2="145.39577" - y2="385.33261" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.67277217" - inkscape:cx="372.04724" - inkscape:cy="526.1811" - 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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="M 189.82425,65.224411 387.89857,389.70213" - id="path7612" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="m 386.88842,387.68183 -171.08084,349.6" - id="path7614" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="M 386.88843,389.70213 736.70578,221.52721" - id="path7616" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8211" - y="385.78098" - x="145.59712" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - xml:space="preserve"><tspan - y="385.78098" - x="145.59712" - id="tspan8213" - sodipodi:role="line" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - x="363.9928" - y="221.1528" - id="text8235" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;" - sodipodi:role="line" - id="tspan8237" - x="363.9928" - y="221.1528">X</tspan></text> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8239" - y="556.086" - x="465.5513" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - xml:space="preserve"><tspan - y="556.086" - x="465.5513" - id="tspan8241" - sodipodi:role="line" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;">X</tspan></text> - </g> -</svg> diff --git a/labs/lab3-k-means/step4.png b/labs/lab3-k-means/step4.png deleted file mode 100644 index 2eafaa4e26f7c97028692716d9474ab3a8ab2482..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/step4.png and /dev/null differ diff --git a/labs/lab3-k-means/step4.svg b/labs/lab3-k-means/step4.svg deleted file mode 100644 index ad37ce85883bf092146048dcfe45c430968e4afd..0000000000000000000000000000000000000000 --- a/labs/lab3-k-means/step4.svg +++ /dev/null @@ -1,441 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" - 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:xlink="http://www.w3.org/1999/xlink" - 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\kmeans\step4.png" - inkscape:export-xdpi="44.18" - inkscape:export-ydpi="44.18" - sodipodi:docname="step4.svg"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker12915" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path12917" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker12465" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend" - inkscape:collect="always"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path12467" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker11619" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path11621" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4153" - 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:1.0pt;" - transform="scale(0.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker10709" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path10711" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker9251" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path9253" /> - </marker> - <marker - inkscape:stockid="Arrow2Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow2Lend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4165" - style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" - d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " - transform="scale(1.1) rotate(180) translate(1,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker8251" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path8253" - 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> - <linearGradient - inkscape:collect="always" - id="linearGradient8215"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop8217" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop8219" /> - </linearGradient> - <linearGradient - id="linearGradient7502" - osb:paint="solid"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop7504" /> - </linearGradient> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4494" - 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="path4496" /> - </marker> - <marker - inkscape:stockid="Arrow1Lend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Lend" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4147" - 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> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8215" - id="linearGradient8221" - x1="119.05175" - y1="385.33261" - x2="145.39577" - y2="385.33261" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.67277217" - inkscape:cx="372.04724" - inkscape:cy="526.1811" - 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.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)" - d="m 41.428567,463.79078 646.353683,0" - id="path4138" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4492" - d="m 338.83255,778.33762 0,-646.35368" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.07530761;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4494)" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke:#000000;stroke-opacity:1" - id="path5826" - cx="475.71429" - cy="179.50507" - r="10" /> - <circle - r="10" - cy="245.21935" - cx="505.71429" - id="circle5828" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5830" - cx="548.57141" - cy="189.50507" - r="10" /> - <circle - r="10" - cy="240.93364" - cx="581.42853" - id="circle5832" - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:0.29677418;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5834" - cx="585.71423" - cy="110.93364" - r="10" /> - <circle - r="10" - cy="316.64792" - cx="98.571434" - id="circle5838" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5840" - cx="302.31769" - cy="302.56015" - r="10" /> - <circle - r="10" - cy="340.79007" - cx="239.10878" - id="circle5842" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle5844" - cx="188.12323" - cy="373.02576" - r="10" /> - <circle - r="10" - cy="262.21863" - cx="227.76428" - id="circle5846" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7532" - cx="70.008804" - cy="691.26898" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="737.31219" - cx="36.781143" - id="circle7534" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7536" - cx="181.05341" - cy="695.65546" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - r="10" - cy="766.3324" - cx="123.32337" - id="circle7538" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <circle - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:2.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle7540" - cx="137.71626" - cy="630.1972" - r="10" - transform="matrix(0.77979134,-0.62603951,0.62603951,0.77979134,0,0)" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="M 189.82425,65.224411 387.89857,389.70213" - id="path7612" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="m 386.88842,387.68183 -171.08084,349.6" - id="path7614" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.5, 7.5;stroke-dashoffset:0;stroke-opacity:1" - d="M 386.88843,389.70213 736.70578,221.52721" - id="path7616" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8211" - y="385.78098" - x="145.59712" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - xml:space="preserve"><tspan - y="385.78098" - x="145.59712" - id="tspan8213" - sodipodi:role="line" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - x="363.9928" - y="221.1528" - id="text8235" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;" - sodipodi:role="line" - id="tspan8237" - x="363.9928" - y="221.1528">X</tspan></text> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text8239" - y="556.086" - x="465.5513" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - xml:space="preserve"><tspan - y="556.086" - x="465.5513" - id="tspan8241" - sodipodi:role="line" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;">X</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" - x="182.62602" - y="355.70956" - id="text11603" - sodipodi:linespacing="125%" - transform="scale(1.1239557,0.88971479)"><tspan - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-opacity:1;" - sodipodi:role="line" - id="tspan11605" - x="182.62602" - y="355.70956">X</tspan></text> - <text - transform="scale(1.1239557,0.88971479)" - sodipodi:linespacing="125%" - id="text11607" - y="240.43587" - x="449.76309" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:35.58874893px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="240.43587" - x="449.76309" - id="tspan11609" - sodipodi:role="line" - style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-opacity:1">X</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 9;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker11619)" - d="M 164.98899,315.1141 C 138.7091,262.04866 179.31776,214.18838 206.60783,282.41357" - id="path11617" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path12463" - d="m 434.02509,162.0162 c 16.82534,-48.60627 60.40678,-45.92938 87.69685,22.2958" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 9;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker12465)" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 9;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker12915)" - d="m 558.88163,474.15753 c 52.49863,-20.36492 73.78426,46.22663 -1.48639,19.32302" - id="path12913" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - </g> -</svg> diff --git a/labs/lab3-k-means/uniform-random-30steps.png b/labs/lab3-k-means/uniform-random-30steps.png deleted file mode 100644 index 3ab1db8db80df4174f75cdd51c0385bce3370dad..0000000000000000000000000000000000000000 Binary files a/labs/lab3-k-means/uniform-random-30steps.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/README.md b/labs/lab4-barnes-hut-simulation/README.md deleted file mode 100644 index ef81cec3c8d45bdd05667cbc1e106e01b74e187a..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/README.md +++ /dev/null @@ -1,560 +0,0 @@ -# Barnes-Hut Simulation - -Use the following commands to make a fresh clone of your repository: - -```sh -git clone -b barneshut git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-barneshut -``` - -## Useful links - - * [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 parallel Barnes-Hut algorithm for *N-body simulation*. -N-body simulation is a simulation of a system of *N* particles that interact with physical -forces, such as gravity or electrostatic force. -Given initial positions and velocities of all the *particles* (or *bodies*), the N-body simulation -computes the new positions and velocities of the particles as the time progresses. -It does so by dividing time into discrete short intervals, and computing the -positions of the particles after each interval. - -<!-- -Let us recall some basics of classical mechanics. -What makes a particle, such as an atom, a comet or a star, move through space? -First, the particle moves through space as a consequence of having some initial velocity -compared to other particles. -Second, the particle changes its velocity as a result of external forces. -These forces are in direct correlation with the proximity of other particles. -For example, Earth moves through space with some initial velocity, -which is constantly being changed due to the gravitational force between the Earth and the Sun. ---> - -Before we study the Barnes-Hut algorithm for the N-body simulation problem, -we will focus on a simpler algorithm -- the *direct sum N-body algorithm*. -The direct sum algorithm consists of multiple iterations, each of which performs -the following steps for each particle: - -1. The particle position is updated according to its current velocity (`delta` is a short time period). - - x' = x + v_x * delta - y' = y + v_y * delta - -2. The net force on the particle is computed by adding the individual forces from all the other particles. - - F_x = F_1x + F_2x + F_3x + ... + F_Nx - F_y = F_1y + F_2y + F_3y + ... + F_Ny - -3. The particle velocity is updated according to the net force on that particle. - - v_x' = v_x + F_x / mass * delta - v_y' = v_y + F_y / mass * delta - -In this exercise, we will assume that the force between particles is the *gravitational force* -from classical mechanics. Let's recall the formula for the gravitational force between two stellar bodies: - - F = G * (m1 * m2) / distance^2 - -Above, `F` is the absolute value of the gravitational force, `m1` and `m2` are the masses of the two bodies, -and `r` is the distance between them. `G` is the gravitational constant. - -<!-- -The gravitational force vector always points towards the other body. -The `F_x` and `F_y` components of the gravitational force on the body `m1` -can be computed by observing the following triangle similarity: - -```scala -distance = math.sqrt((x2 - x1) ^ 2 + (y2 - y1) ^ 2) -F_x / F = (x2 - x1) / distance -F_y / F = (y2 - y1) / distance -``` - -This is shown in the following figure: - - ---> - -For each particle, the net force is computed by summing the components of individual forces from all other particles, -as shown in the following figure: - - - -The direct sum N-body algorithm is very simple, but also inefficient. -Since we need to update `N` particles, and compute `N - 1` force contributions for each of those particles, -the overall complexity of an iteration step of this algorithm is `O(N^2)`. -As the number of particles grows larger, the direct sum N-body algorithm becomes prohibitively expensive. - -The Barnes-Hut algorithm is an optimization of the direct sum N-body algorithm, -and is based on the following observation: - -> If a cluster of bodies is sufficiently distant from a body *A*, the net force on *A* -> from that cluster can be approximated with one big body with the mass of all the -> bodies in the cluster, positioned at the center of mass of the cluster. - -This is illustrated in the following figure: - - - -To take advantage of this observation, the Barnes-Hut algorithm relies on -a *quadtree* -- a data structure that divides the space into cells, and answers queries -such as 'What is the total mass and the center of mass of all the particles in this cell?'. -The following figure shows an example of a quadtree for 6 bodies: - - - -Above, the total force from the bodies *B*, *C*, *D* and *E* on the body *A* can be approximated -by a single body with *mass* equal to the sum of masses *B*, *C*, *D* and *E*, -positioned at the center of mass of bodies *B*, *C*, *D* and *E*. -The center of mass `(massX, massY)` is computed as follows: - -```scala -mass = m_B + m_C + m_D + m_E -massX = (m_B * x_B + m_C * x_C + m_D * x_D + m_E * x_E) / mass -massY = (m_B * y_B + m_C * y_C + m_D * y_D + m_E * y_E) / mass -``` -An iteration of the Barnes-Hut algorithm is composed of the following steps: - -1. Construct the quadtree for the current arrangement of the bodies. - 1. Determine the *boundaries*, i.e. the square into which all bodies fit. - 2. Construct a quadtree that covers the boundaries and contains all the bodies. -2. Update the bodies -- for each body: - 1. Update the body position according to its current velocity. - 2. Using the quadtree, compute the net force on the body by adding the individual forces from all the other bodies. - 3. Update the velocity according to the net force on that body. - -It turns out that, for most spatial distribution of bodies, -the expected number of cells that contribute to the net force on a body is `log n`, -so the overall complexity of the Barnes-Hut algorithm is `O(n log n)`. - -Now that we covered all the necessary theory, let's finally dig into the implementation! -You will implement: - -- a quadtree and its combiner data structure -- an operation that computes the total force on a body using the quadtree -- a simulation step of the Barnes-Hut algorithm - -Since this assignment consists of multiple components, -we will follow the principles of *test-driven development* and test each component separately, -before moving on to the next component. -That way, if anything goes wrong, we will more precisely know where the error is. -It is always better to detect errors sooner, rather than later. - - -## Data Structures - -We will start by implementing the necessary data structures: the quadtree, -the body data-type and the sector matrix. -You will find the stubs in the `package.scala` file of the `barneshut` package. - - -### Quadtree Data Structure - -In this part of the assignment, we implement the quadtree data structure, -denoted with the abstract data-type `Quad`. -Every `Quad` represents a square cell of space, and can be one of the following node types: - -- an `Empty` node, which represents an empty quadtree -- a `Leaf` node, which represents one or more bodies -- a `Fork` node, which divides a spatial cell into four quadrants - -The definition of `Quad` is as follows: - -```scala -sealed abstract class Quad { - def massX: Float - def massY: Float - def mass: Float - def centerX: Float - def centerY: Float - def size: Float - def total: Int - def insert(b: Body): Quad -} -``` - -Here, `massX` and `massY` represent the center of mass of the bodies in the respective cell, -`mass` is the total mass of bodies in that cell, `centerX` and `centerY` are the coordinates -of the center of the cell, `size` is the length of the side of the cell, -and `total` is the total number of bodies in the cell. - -Note that we consider the top left corner to be at coordinate (0, 0). We also consider the x axis to grow to the right and the y axis to the bottom. - - - -The method `insert` creates a new quadtree which additionally contains the body `b`, -and covers the same area in space as the original quadtree. -Quadtree is an *immutable* data structure -- `insert` does not modify the existing `Quad` object. -Note that `Body` has the following signature: - -```scala -class Body(val mass: Float, val x: Float, val y: Float, val xspeed: Float, val yspeed: Float) -``` - -In this part of the exercise, you only need to know about body's position `x` and `y`. - -Let's start by implementing the simplest `Quad` type -- the empty quadtree: - -```scala -case class Empty(centerX: Float, centerY: Float, size: Float) extends Quad -``` - -The center and the size of the `Empty` quadtree are specified in its constructor. -The `Empty` tree does not contain any bodies, so we specify that its center of mass is equal to its center. - -Next, let's implement the `Fork` quadtree: - -```scala -case class Fork(nw: Quad, ne: Quad, sw: Quad, se: Quad) extends Quad -``` - -This node is specified by four child quadtrees `nw`, `ne`, `sw` and `se`, -in the northwest, northeast, southwest and southeast quadrant, respectively. - -The northwest is located on the top left, northeast on the top right, southwest on the bottom left and southeast on the bottom right. - -The constructor assumes that the children nodes that represent four adjacent cells of the -same size and adjacent to each other, as in the earlier figure. -The center of the `Fork` quadtree is then specified by, say, the -lower right corner of the quadtree `nw`. If the `Fork` quadtree is empty, the -center of mass coincides with the center. - -Inserting into a `Fork` is recursive -- it updates the respective child and creates a new `Fork`. - -Finally, the `Leaf` quadtree represents one or more bodies: - -```scala -case class Leaf(centerX: Float, centerY: Float, size: Float, bodies: Seq[Body]) -extends Quad -``` - -If the `size` of a `Leaf` is greater than a predefined constant `minimumSize`, -inserting an additonal body into that `Leaf` quadtree creates a `Fork` quadtree -with empty children, and adds all the bodies into that `Fork` (including the new body). -Otherwise, inserting creates another `Leaf` with all the existing bodies and the new one. - - -### The Body Data-Type - -Next, we can implement the `Body` data-type: - -```scala -class Body(val mass: Float, val x: Float, val y: Float, val xspeed: Float, val yspeed: Float) { - def updated(quad: Quad): Body = ??? -} -``` - -Here, `xspeed` and `yspeed` represent the velocity of the body, `mass` is its mass, -and `x` and `y` are the coordinates of the body. - -The most interesting method on the `Body` is `updated` -- it takes a quadtree and -returns the updated version of the `Body`: - -```scala -def updated(quad: Quad): Body -``` - -This method is already half-completed for you -- you only need to implement -its nested method `traverse`, which goes through the quadtree and proceeds casewise: - -- empty quadtree does not affect the net force -- each body in a leaf quadtree adds some net force -- a fork quadtree that is sufficiently far away acts as a single point of mass -- a fork quadtree that is not sufficiently far away must be recursively traversed - -When are we allowed to approximate a cluster of bodies with a single point? -The heuristic that is used is that the size of the cell divided by the distance -`dist` between the center of mass and the particle is less than some constant `theta`: - -```scala -quad.size / dist < theta -``` - -Hint: make sure you use the `distance` to compute distance between points, -the `theta` value for the condition, and `addForce` to add force contributions! - -Before proceeding, make sure to run tests against your `Quad` and `Body` implementations. - - -### The Sector Matrix - -The last data structure that we will implement is the *sector matrix*. -In this data structure, we will use the auxiliary class `Boundaries`, which -contains the `minX`, `maxX`, `minY` and `maxY` fields for the boundaries of the scene: - -```scala -class Boundaries { - var minX: Float - var minY: Float - var maxX: Float - var maxY: Float - def size = math.max(maxX - minX, maxY - minY) -} -``` - -We will also rely on the `ConcBuffer` data structure, mentioned in the lecture: - -```scala -class ConcBuffer[T] -``` - -The `ConcBuffer` class comes with efficient `+=`, `combine` and `foreach` operations, -which add elements into the buffer, combine two buffers and traverse the buffer, respectively. -The sector matrix additionally has the `toQuad` method, which returns a quadtree that contains all -the elements previously added with the `+=` method. -Recall from the lectures that this combination of methods make the `ConcBuffer` a *combiner*. - -The `SectorMatrix` is just a square matrix that covers a square region of space -specified by the boundaries: - -```scala -class SectorMatrix(val boundaries: Boundaries, val sectorPrecision: Int) { - val sectorSize = boundaries.size / sectorPrecision - val matrix = new Array[ConcBuffer[Body]](sectorPrecision * sectorPrecision) - for (i <- 0 until matrix.length) matrix(i) = new ConcBuffer - def apply(x: Int, y: Int) = matrix(y * sectorPrecision + x) -} -``` - -The `sectorPrecision` argument denotes the width and height of the matrix, and -each entry contains a `ConcBuffer[Body]` object. Effectively, the `SectorMatrix` is a *combiner* -- -it partitions the square region of space into `sectorPrecision` times `sectorPrecision` buckets, called *sectors*. - - - -Combiners such as the `SectorMatrix` are used in parallel programming to partition the results into -some intermediate form that is more amenable to parallelization. -Recall from the lecture that one of the ways to implement a *combiner* is by using -a bucket data structure -- we will do exactly that in this part of the exercise! -We will add three methods on the `SectorMatrix` that will make it a combiner. -We start with the `+=` method: - -```scala -def +=(b: Body): SectorMatrix = { - ??? - this -} -``` - -This method should use the body position, `boundaries` and `sectorPrecision` -to determine the sector into which the body should go into, -and add the body into the corresponding `ConcBuffer` object. - -Importantly, if the `Body` lies outside of the `Boundaries`, it should be considered -to be located at the closest point within the `Boundaries` for the purpose of finding which `ConcBuffer` should hold the body. - -Next, we implement the `combine` method, which takes another `SectorMatrix`, -and creates a `SectorMatrix` which contains the elements of both input -`SectorMatrix` data structures: - -```scala -def combine(that: SectorMatrix): SectorMatrix -``` - -This method calls `combine` on the pair of `ConcBuffer`s in `this` and `that` -matrices to produce the `ConcBuffer` for the resulting matrix. -You can safely assume that combine will only be called on matrices of same dimensions, boundaries and sector precision. - - - - -The nice thing about the sector matrix is that a quadtree can be constructed -in parallel for each sector. Those little quadtrees can then be linked together. -The `toQuad` method on the `SectorMatrix` does this: - -```scala -def toQuad(parallelism: Int): Quad -``` - -This method is already implemented -- you can examine -it if you would like to know how it works. - -<!-- -Finally, we will implement the `toQuad` method, which uses the `SectorMatrix` -to create a `Quad` tree in parallel: - -```scala -def toQuad(parallelism: Int): Quad = { - def BALANCING_FACTOR = 4 - def quad(x: Int, y: Int, span: Int, achievedParallelism: Int): Quad = { - if (span == 1) { - ??? - } else { - ??? - } - } - quad(0, 0, sectorPrecision, 1) -} -``` - -The `toQuad` method takes the desired degree of `parallelism` as an argument, -and then calls the recursive `quad` method. -The `quad` method operates on a subsquare of the matrix starting at `x`, `y` coordinates, -with the length `span`. -The fourth parameter, `achievedParallelism`, describes how many tasks have been -created at a given call depth. - -Implement the `quad` method so that: - -1. If `span` is 1, the method sequentially converts the bodies in that sector to a quadtree. - Use `foldLeft` and the `insert` method on the bodies in each sector to get the quadtree. -2. Otherwise, if `parallelism > 1 && achievedParallelism < parallelism * BALANCING_FACTOR`, - the method recursively, and in parallel, creates quadtrees for the `4` subsquares - and links them together into a bigger quadtree. -3. Otherwise, if the `parallelism == 1 || achievedParallelism >= parallelism * BALANCING_FACTOR`, - the method does the same as in case 2, but without parallelism. - -Don't forget to multiply `achievedParallelism` by `4` at each step. ---> - -Congratulations, you just implemented your first combiner! -Before proceeding, make sure to run those unit tests. - - -## Implementing Barnes-Hut - -Now that we have all the right data structures ready and polished, -implementing Barnes-Hut becomes a piece of cake. - -Take a look at the file `Simulator.scala`, which contains the implementation -of the Barnes-Hut simulator, and in particular the `step` method. -The `step` method represents one step in the simulation: - -```scala -def step(bodies: Seq[Body]): (Seq[Body], Quad) = { - // 1. compute boundaries - val boundaries = computeBoundaries(bodies) - - // 2. compute sector matrix - val sectorMatrix = computeSectorMatrix(bodies, boundaries) - - // 3. compute quadtree - val quad = computeQuad(sectorMatrix) - - // 4. eliminate outliers - val filteredBodies = eliminateOutliers(bodies, sectorMatrix, quad) - - // 5. update body velocities and positions - val newBodies = updateBodies(filteredBodies, quad) - - (newBodies, quad) -} -``` - -The pre-existing code in `step` nicely summarizes what this method does. - - -### Computing the Scene Boundaries - -First, we must compute the boundaries of all the bodies in the scene. -Since bodies move and the boundaries dynamically change, -we must do this in every iteration of the algorithm. -The `computeBoundaries` method is already implemented -- it uses the `aggregate` -combinator on the sequence of bodies to compute the boundaries: - -```scala -def computeBoundaries(bodies: Seq[Body]): Boundaries = { - val parBodies = bodies.par - parBodies.tasksupport = taskSupport - parBodies.aggregate(new Boundaries)(updateBoundaries, mergeBoundaries) -} -``` - -How does this work? The `aggregate` method divides the input sequence into a -number of chunks. For each of the chunks, it uses the `new Boundaries` expression -to create the accumulation value, and then folds the values in that chunk -calling `updateBoundaries` on each body, in the same way a `foldLeft` operation would. -Finally, `aggregate` combines the results of different chunks using a reduction tree and `mergeBoundaries`. - -So, we need the `updateBoundaries` method: - -```scala -def updateBoundaries(boundaries: Boundaries, body: Body): Boundaries -``` - -Given an existing `boundaries` object and a body, the `updateBoundaries` updates -the `minX`, `minY`, `maxX` and `maxY` values so that the boundaries include the body. - -Next, the `mergeBoundaries` method creates a new `Boundaries` object, which represents -the smallest rectangle that contains both the input boundaries: - -```scala -def mergeBoundaries(a: Boundaries, b: Boundaries): Boundaries -``` - -Question: Is `mergeBoundaries` associative? Is it commutative? Does it need to be commutative? - -Implement these two methods, and test that they work correctly! - - -### Building the Quadtree - -Next, we need to build a `Quad` tree from the sequence of bodies. -We will first implement the `computeSectorMatrix` method to get the `SectorMatrix`: - -```scala -def computeSectorMatrix(bodies: Seq[Body], boundaries: Boundaries): SectorMatrix -``` - -Hint: aggregate the `SectorMatrix` from the sequence of bodies, the same way it was used for boundaries. -Use the SECTOR_PRECISION constant when creating a new `SectorMatrix`. - -<!-- -Next, implement `computeQuad`, which converts `SectorMatrix` to a `Quad`: - - def computeQuad(sectorMatrix: SectorMatrix): Quad - -Hint: use `taskSupport.parallelismLevel` to determine the desired parallelism. ---> - -Test that these methods work correctly before proceeding! - - -### Eliminating Outliers - -During the execution of the Barnes-Hut algorithm, some of the bodies tend to -move far away from most of the other bodies. There are many ways to deal with such *outliers*, -but to keep things simple, we will eliminate bodies that move too fast and too far away. - -We will not go into details of how this works, but if you'd like to know more, -you can try to understand how the `eliminateOutliers` method works. - - -### Updating Bodies - -The `updateBodies` method uses the quadtree to map each body from the -previous iteration of the algorithm to a new iteration: - -```scala -def updateBodies(bodies: Seq[Body], quad: Quad): Seq[Body] -``` - -Recall that we already implemented the `updated` method which updates a single body. - - -## Running Barnes-Hut - -At last, the parallel Barnes-Hut algorithm is implemented. -Note that, despite all the work, we kept our Barnes-Hut algorithm implementation simple -and avoided the details that a more realistic implementation must address. In particular: - -- we represented each body as a single point in space -- we restricted the simulation to two-dimensional space -- we ignored close encounter effects, such as body collision or tearing -- we ignored any relativistic effects, and assume classical mechanics -- we ignored errors induced by floating point computations - -You can now run it as follows: - - > runMain barneshut.BarnesHut - -To visualize the quadtree, press the *Show quad* button, and then hit the *Start/Pause* button. - -Play with the parallelism level and the number of bodies, and observe the average speedups in the lower right corner. -Then sit back, and enjoy the show! - diff --git a/labs/lab4-barnes-hut-simulation/cell.png b/labs/lab4-barnes-hut-simulation/cell.png deleted file mode 100644 index ad65b0d35f23d5c3bc891a5ee2d6f1fa1e708a53..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/cell.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/cell.svg b/labs/lab4-barnes-hut-simulation/cell.svg deleted file mode 100644 index 28ac7ec2f09622bcddfd8bce0f1894b12338af30..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/cell.svg +++ /dev/null @@ -1,438 +0,0 @@ -<?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="cell.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\cell.png" - inkscape:export-xdpi="32.65155" - inkscape:export-ydpi="32.65155"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15906" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path15908" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker15306" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path15308" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15086" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path15088" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15028" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path15030" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker11876" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path11878" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker10168" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path10170" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker7470" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path7472" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4228" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4231" - 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.4) rotate(180) translate(10,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.7" - inkscape:cx="970.66221" - inkscape:cy="85.954979" - 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"> - <circle - r="13.141105" - cy="721.93744" - cx="1136.2686" - id="circle4144" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <text - sodipodi:linespacing="125%" - id="text4152" - y="748.34113" - x="1165.1003" - 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="748.34113" - x="1165.1003" - id="tspan4154" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4158">E</tspan></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="1152.1206" - y="688.21014" - id="text7888" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7890" - x="1152.1206" - y="688.21014">(x<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14976">E</tspan>,y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14974">E</tspan>)</tspan></text> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle8064" - cx="1028.7399" - cy="1061.7242" - r="13.141105" /> - <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="1055.5515" - y="1070.8625" - id="text8066" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan8068" - x="1055.5515" - y="1070.8625">m<tspan - id="tspan8070" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan></tspan></text> - <circle - r="13.141105" - cy="653.45074" - cx="741.34894" - id="circle10468" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <text - sodipodi:linespacing="125%" - id="text10470" - y="682.58905" - x="766.01764" - 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="682.58905" - x="766.01764" - id="tspan10472" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan10474">D</tspan></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="743.56964" - y="1123.7406" - id="text10476" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan10478" - x="743.56964" - y="1123.7406">m<tspan - id="tspan10480" - style="font-size:64.99999762%;baseline-shift:sub">B</tspan></tspan></text> - <circle - r="13.141105" - cy="1088.6008" - cx="727.80518" - id="circle10482" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="952.23749" - y="908.33813" - id="text13406" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan13408" - x="952.23749" - y="908.33813">mass</tspan></text> - <circle - r="24.149361" - cy="893.79889" - cx="923.70862" - id="circle13404" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:10, 5;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="558.17084" - x="604.85461" - height="531.79376" - width="531.79376" - id="rect14954" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="-822.98016" - x="-869.66394" - height="264.46457" - width="264.46457" - id="rect14958" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="scale(-1,-1)" /> - <rect - transform="scale(-1,-1)" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5.03303289;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect14960" - width="267.3674" - height="266.65311" - x="-1136.4081" - y="-1089.01" /> - <text - sodipodi:linespacing="125%" - id="text14978" - y="619.51978" - x="717.755" - 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="619.51978" - x="717.755" - id="tspan14980" - sodipodi:role="line">(x<tspan - id="tspan14982" - style="font-size:64.99999762%;baseline-shift:sub">D</tspan>,y<tspan - id="tspan14984" - style="font-size:64.99999762%;baseline-shift:sub">D</tspan>)</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="646.05164" - y="1057.5076" - id="text14986" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan14988" - x="646.05164" - y="1057.5076">(x<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14990">B</tspan>,y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14992">B</tspan>)</tspan></text> - <text - sodipodi:linespacing="125%" - id="text14994" - y="1044.3879" - x="882.93494" - 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="1044.3879" - x="882.93494" - id="tspan14996" - sodipodi:role="line">(x<tspan - id="tspan14998" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan>,y<tspan - id="tspan15000" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan>)</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:100%;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="895.39038" - y="954.85413" - id="text15002" - sodipodi:linespacing="100%" - inkscape:export-xdpi="34.630001" - inkscape:export-ydpi="34.630001"><tspan - sodipodi:role="line" - id="tspan15004" - x="895.39038" - y="954.85413" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">(mass<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15020">X</tspan>,mass<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15016">Y</tspan>)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4.89491892;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker15028);marker-end:url(#marker15086)" - d="m 611.75315,1157.4181 516.98645,0" - id="path15026" - 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="825.29462" - y="1220.0476" - id="text15252" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan15254" - x="825.29462" - y="1220.0476">size<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15256" /></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="1248.5714" - y="899.50507" - id="text4276" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4278" - x="1248.5714" - y="899.50507">total=4</tspan></text> - <text - inkscape:export-ydpi="34.630001" - inkscape:export-xdpi="34.630001" - sodipodi:linespacing="100%" - id="text4280" - y="793.42554" - x="875.39038" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:100%;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 - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start" - y="793.42554" - x="875.39038" - id="tspan4282" - sodipodi:role="line">(center<tspan - id="tspan4284" - style="font-size:64.99999762%;baseline-shift:sub">X</tspan>,center<tspan - id="tspan4286" - style="font-size:64.99999762%;baseline-shift:sub">Y</tspan>)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:11.70279694;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 854.21813,808.4712 31.66682,31.66682" - id="path4288" - inkscape:connector-curvature="0" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:11.70279694;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="m 855.14272,840.36917 32.36025,-32.36026" - id="path4290" - inkscape:connector-curvature="0" /> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/combine.png b/labs/lab4-barnes-hut-simulation/combine.png deleted file mode 100644 index f54059cf101152332af25658cc26e5bd29c2c694..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/combine.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/combine.svg b/labs/lab4-barnes-hut-simulation/combine.svg deleted file mode 100644 index 09fb5286d7e6f23a9e1274a6cc70ae1476562769..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/combine.svg +++ /dev/null @@ -1,1082 +0,0 @@ -<?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="combine.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\sectormatrix.png" - inkscape:export-xdpi="32.6516" - inkscape:export-ydpi="32.6516"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="marker4830" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4832" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Sstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Sstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4202" - 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.2) translate(6,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="370.35135" - inkscape:cy="411.90881" - 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"> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4138" - width="157.25688" - height="157.25688" - x="746.3056" - y="293.24829" /> - <rect - y="293.24829" - x="903.69269" - height="157.25688" - width="157.25688" - id="rect4140" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="293.24829" - x="1060.2903" - height="157.25688" - width="157.25688" - id="rect4142" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4144" - width="157.25688" - height="157.25688" - x="1217.6774" - y="293.24829" /> - <rect - y="450.89859" - x="746.3056" - height="157.25688" - width="157.25688" - id="rect4146" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4148" - width="157.25688" - height="157.25688" - x="903.69269" - y="450.89859" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4150" - width="157.25688" - height="157.25688" - x="1060.2903" - y="450.89859" /> - <rect - y="450.89859" - x="1217.6774" - height="157.25688" - width="157.25688" - id="rect4152" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="608.02252" - x="746.3056" - height="157.25688" - width="157.25688" - id="rect4154" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4156" - width="157.25688" - height="157.25688" - x="903.69269" - y="608.02252" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4158" - width="157.25688" - height="157.25688" - x="1060.2903" - y="608.02252" /> - <rect - y="608.02252" - x="1217.6774" - height="157.25688" - width="157.25688" - id="rect4160" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4162" - width="157.25688" - height="157.25688" - x="746.3056" - y="765.67279" /> - <rect - y="765.67279" - x="903.69269" - height="157.25688" - width="157.25688" - id="rect4164" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="765.67279" - x="1060.2903" - height="157.25688" - width="157.25688" - id="rect4166" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4168" - width="157.25688" - height="157.25688" - x="1217.6774" - y="765.67279" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4170" - cx="1020.8884" - cy="491.64792" - r="13.571428" /> - <circle - r="13.571428" - cy="854.50507" - cx="1285.1742" - id="circle4172" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4174" - cx="1355.1742" - cy="824.50507" - r="13.571428" /> - <circle - r="13.571428" - cy="894.50507" - cx="1376.6028" - id="circle4176" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4178" - cx="1312.3171" - cy="295.93362" - r="13.571428" /> - <circle - r="13.571428" - cy="805.93365" - cx="853.74573" - id="circle4180" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4182" - cx="1141.0917" - cy="717.37964" - r="13.571428" /> - <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="757.61438" - y="345.25543" - id="text5218" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5220" - x="757.61438" - y="345.25543">0,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5222" - y="345.25543" - x="927.32001" - 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="345.25543" - x="927.32001" - id="tspan5224" - sodipodi:role="line">1,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="1080.8633" - y="345.25543" - id="text5226" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5228" - x="1080.8633" - y="345.25543">2,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5230" - y="345.25543" - x="1236.4268" - 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="345.25543" - x="1236.4268" - id="tspan5232" - sodipodi:role="line">3,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5234" - y="504.85953" - x="757.61438" - 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="504.85953" - x="757.61438" - id="tspan5236" - sodipodi:role="line">0,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="927.32001" - y="504.85953" - id="text5238" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5240" - x="927.32001" - y="504.85953">1,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5242" - y="504.85953" - x="1080.8633" - 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="504.85953" - x="1080.8633" - id="tspan5244" - sodipodi:role="line">2,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="1236.4268" - y="504.85953" - id="text5246" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5248" - x="1236.4268" - y="504.85953">3,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="757.61438" - y="656.38239" - id="text5250" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5252" - x="757.61438" - y="656.38239">0,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5254" - y="656.38239" - x="927.32001" - 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="656.38239" - x="927.32001" - id="tspan5256" - sodipodi:role="line">1,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="1080.8633" - y="656.38239" - id="text5258" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5260" - x="1080.8633" - y="656.38239">2,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5262" - y="656.38239" - x="1236.4268" - 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="656.38239" - x="1236.4268" - id="tspan5264" - sodipodi:role="line">3,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5266" - y="813.96619" - x="757.61438" - 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="813.96619" - x="757.61438" - id="tspan5268" - sodipodi:role="line">0,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="927.32001" - y="813.96619" - id="text5270" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5272" - x="927.32001" - y="813.96619">1,3</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5274" - y="813.96619" - x="1080.8633" - 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="813.96619" - x="1080.8633" - id="tspan5276" - sodipodi:role="line">2,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="1236.4268" - y="813.96619" - id="text5278" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5280" - x="1236.4268" - y="813.96619">3,3</tspan></text> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4209" - cx="1180.1184" - cy="684.79944" - r="13.571428" /> - <circle - r="13.571428" - cy="884.80963" - cx="800.30096" - id="circle4211" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="293.24829" - x="-243.64386" - height="157.25688" - width="157.25688" - id="rect4213" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4215" - width="157.25688" - height="157.25688" - x="-86.256775" - y="293.24829" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4217" - width="157.25688" - height="157.25688" - x="70.340759" - y="293.24829" /> - <rect - y="293.24829" - x="227.72791" - height="157.25688" - width="157.25688" - id="rect4219" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4221" - width="157.25688" - height="157.25688" - x="-243.64386" - y="450.89859" /> - <rect - y="450.89859" - x="-86.256775" - height="157.25688" - width="157.25688" - id="rect4223" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="450.89859" - x="70.340759" - height="157.25688" - width="157.25688" - id="rect4225" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4227" - width="157.25688" - height="157.25688" - x="227.72791" - y="450.89859" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4229" - width="157.25688" - height="157.25688" - x="-243.64386" - y="608.02252" /> - <rect - y="608.02252" - x="-86.256775" - height="157.25688" - width="157.25688" - id="rect4231" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="608.02252" - x="70.340759" - height="157.25688" - width="157.25688" - id="rect4233" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4235" - width="157.25688" - height="157.25688" - x="227.72791" - y="608.02252" /> - <rect - y="765.67279" - x="-243.64386" - height="157.25688" - width="157.25688" - id="rect4237" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4239" - width="157.25688" - height="157.25688" - x="-86.256775" - y="765.67279" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4241" - width="157.25688" - height="157.25688" - x="70.340759" - y="765.67279" /> - <rect - y="765.67279" - x="227.72791" - height="157.25688" - width="157.25688" - id="rect4243" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - r="13.571428" - cy="824.50507" - cx="365.22473" - id="circle4249" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - r="13.571428" - cy="295.93362" - cx="322.36768" - id="circle4253" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4255" - cx="-136.20374" - cy="805.93365" - r="13.571428" /> - <text - sodipodi:linespacing="125%" - id="text4259" - y="345.25543" - x="-232.33508" - 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="345.25543" - x="-232.33508" - id="tspan4261" - sodipodi:role="line">0,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="-62.629456" - y="345.25543" - id="text4263" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4265" - x="-62.629456" - y="345.25543">1,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4267" - y="345.25543" - x="90.913757" - 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="345.25543" - x="90.913757" - id="tspan4269" - sodipodi:role="line">2,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="246.47729" - y="345.25543" - id="text4271" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4273" - x="246.47729" - y="345.25543">3,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="-232.33508" - y="504.85953" - id="text4275" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4277" - x="-232.33508" - y="504.85953">0,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4279" - y="504.85953" - x="-62.629456" - 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="504.85953" - x="-62.629456" - id="tspan4281" - sodipodi:role="line">1,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="90.913757" - y="504.85953" - id="text4283" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4285" - x="90.913757" - y="504.85953">2,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4287" - y="504.85953" - x="246.47729" - 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="504.85953" - x="246.47729" - id="tspan4289" - sodipodi:role="line">3,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4291" - y="656.38239" - x="-232.33508" - 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="656.38239" - x="-232.33508" - id="tspan4293" - sodipodi:role="line">0,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="-62.629456" - y="656.38239" - id="text4295" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4297" - x="-62.629456" - y="656.38239">1,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4299" - y="656.38239" - x="90.913757" - 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="656.38239" - x="90.913757" - id="tspan4301" - sodipodi:role="line">2,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="246.47729" - y="656.38239" - id="text4303" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4305" - x="246.47729" - y="656.38239">3,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="-232.33508" - y="813.96619" - id="text4307" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4309" - x="-232.33508" - y="813.96619">0,3</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4311" - y="813.96619" - x="-62.629456" - 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="813.96619" - x="-62.629456" - id="tspan4313" - sodipodi:role="line">1,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="90.913757" - y="813.96619" - id="text4315" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4317" - x="90.913757" - y="813.96619">2,3</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4319" - y="813.96619" - x="246.47729" - 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="813.96619" - x="246.47729" - id="tspan4321" - sodipodi:role="line">3,3</tspan></text> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4327" - width="157.25688" - height="157.25688" - x="-1231.5731" - y="293.24829" /> - <rect - y="293.24829" - x="-1074.1859" - height="157.25688" - width="157.25688" - id="rect4329" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="293.24829" - x="-917.58844" - height="157.25688" - width="157.25688" - id="rect4331" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4333" - width="157.25688" - height="157.25688" - x="-760.20129" - y="293.24829" /> - <rect - y="450.89859" - x="-1231.5731" - height="157.25688" - width="157.25688" - id="rect4335" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4337" - width="157.25688" - height="157.25688" - x="-1074.1859" - y="450.89859" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4339" - width="157.25688" - height="157.25688" - x="-917.58844" - y="450.89859" /> - <rect - y="450.89859" - x="-760.20129" - height="157.25688" - width="157.25688" - id="rect4341" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="608.02252" - x="-1231.5731" - height="157.25688" - width="157.25688" - id="rect4343" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4345" - width="157.25688" - height="157.25688" - x="-1074.1859" - y="608.02252" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4347" - width="157.25688" - height="157.25688" - x="-917.58844" - y="608.02252" /> - <rect - y="608.02252" - x="-760.20129" - height="157.25688" - width="157.25688" - id="rect4349" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4351" - width="157.25688" - height="157.25688" - x="-1231.5731" - y="765.67279" /> - <rect - y="765.67279" - x="-1074.1859" - height="157.25688" - width="157.25688" - id="rect4353" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="765.67279" - x="-917.58844" - height="157.25688" - width="157.25688" - id="rect4355" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4357" - width="157.25688" - height="157.25688" - x="-760.20129" - y="765.67279" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4359" - cx="-956.99023" - cy="491.64792" - r="13.571428" /> - <circle - r="13.571428" - cy="854.50507" - cx="-692.70447" - id="circle4361" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - r="13.571428" - cy="894.50507" - cx="-601.27588" - id="circle4365" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4371" - cx="-836.78705" - cy="717.37964" - r="13.571428" /> - <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="-1220.2643" - y="345.25543" - id="text4373" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4375" - x="-1220.2643" - y="345.25543">0,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4377" - y="345.25543" - x="-1050.5586" - 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="345.25543" - x="-1050.5586" - id="tspan4379" - sodipodi:role="line">1,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="-897.01544" - y="345.25543" - id="text4381" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4383" - x="-897.01544" - y="345.25543">2,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4385" - y="345.25543" - x="-741.4519" - 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="345.25543" - x="-741.4519" - id="tspan4387" - sodipodi:role="line">3,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4389" - y="504.85953" - x="-1220.2643" - 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="504.85953" - x="-1220.2643" - id="tspan4391" - sodipodi:role="line">0,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="-1050.5586" - y="504.85953" - id="text4393" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4395" - x="-1050.5586" - y="504.85953">1,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4397" - y="504.85953" - x="-897.01544" - 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="504.85953" - x="-897.01544" - id="tspan4399" - sodipodi:role="line">2,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="-741.4519" - y="504.85953" - id="text4401" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4403" - x="-741.4519" - y="504.85953">3,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="-1220.2643" - y="656.38239" - id="text4405" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4407" - x="-1220.2643" - y="656.38239">0,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4409" - y="656.38239" - x="-1050.5586" - 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="656.38239" - x="-1050.5586" - id="tspan4411" - sodipodi:role="line">1,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="-897.01544" - y="656.38239" - id="text4413" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4415" - x="-897.01544" - y="656.38239">2,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4417" - y="656.38239" - x="-741.4519" - 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="656.38239" - x="-741.4519" - id="tspan4419" - sodipodi:role="line">3,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4421" - y="813.96619" - x="-1220.2643" - 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="813.96619" - x="-1220.2643" - id="tspan4423" - sodipodi:role="line">0,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="-1050.5586" - y="813.96619" - id="text4425" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4427" - x="-1050.5586" - y="813.96619">1,3</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4429" - y="813.96619" - x="-897.01544" - 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="813.96619" - x="-897.01544" - id="tspan4431" - sodipodi:role="line">2,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="-741.4519" - y="813.96619" - id="text4433" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4435" - x="-741.4519" - y="813.96619">3,3</tspan></text> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4437" - cx="-797.76031" - cy="684.79944" - r="13.571428" /> - <circle - r="13.571428" - cy="884.80963" - cx="-1177.5776" - id="circle4439" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:61.06264496px;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="-556.66376" - y="625.3916" - id="text4441" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4443" - x="-556.66376" - y="625.3916">combine</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4445" - y="668.05292" - x="504.32611" - style="font-style:normal;font-weight:normal;font-size:151.51826477px;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="668.05292" - x="504.32611" - id="tspan4447" - sodipodi:role="line">=</tspan></text> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/force-components.png b/labs/lab4-barnes-hut-simulation/force-components.png deleted file mode 100644 index 455cd799507df3eb94731acb4f0275a252fb6fe5..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/force-components.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/force_components.svg b/labs/lab4-barnes-hut-simulation/force_components.svg deleted file mode 100644 index 265c77f152b2ad67570dc885c8d7c73a85976350..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/force_components.svg +++ /dev/null @@ -1,343 +0,0 @@ -<?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="force_components.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\force-components.png" - inkscape:export-xdpi="43.470001" - inkscape:export-ydpi="43.470001"> - <defs - id="defs4"> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker7470" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path7472" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker6528" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path6530" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker5832" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend" - inkscape:collect="always"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path5834" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4718" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path4720" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker4622" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4624" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4228" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4231" - 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.4) rotate(180) translate(10,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="596.83099" - inkscape:cy="659.30507" - 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"> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4142" - cx="269.28571" - cy="190.21935" - r="13.141105" /> - <circle - r="13.141105" - cy="470.63928" - cx="802.48016" - id="circle4144" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="267.72015" - y="150.9595" - id="text4146" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4148" - x="267.72015" - y="150.9595">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4150">1</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4152" - y="460.49185" - x="837.86316" - 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="460.49185" - x="837.86316" - id="tspan4154" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4158">2</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4160" - y="178.65207" - x="113.20886" - 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="178.65207" - x="113.20886" - id="tspan4162" - sodipodi:role="line">(x<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4180">1</tspan>,y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4178">1</tspan>)</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="817.0473" - y="529.71088" - id="text4182" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4184" - x="817.0473" - y="529.71088">(x<tspan - id="tspan4186" - style="font-size:64.99999762%;baseline-shift:sub">2</tspan>,y<tspan - id="tspan4188" - style="font-size:64.99999762%;baseline-shift:sub">2</tspan>)</tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4622)" - d="m 269.71073,191.71224 0,272.93917" - id="path4190" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.90697932;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Mstart)" - d="m 782.93078,471.122 -512.2099,0" - id="path4192" - inkscape:connector-curvature="0" - 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="452.44324" - y="517.38312" - id="text4182-2" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4184-5" - x="452.44324" - y="517.38312">x<tspan - id="tspan4186-4" - style="font-size:64.99999762%;baseline-shift:sub">2</tspan>-x<tspan - id="tspan4188-5" - style="font-size:64.99999762%;baseline-shift:sub">1</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4614" - y="380.34897" - x="152.27205" - 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="380.34897" - x="152.27205" - id="tspan4616" - sodipodi:role="line">y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4618">2</tspan>-y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4620">1</tspan></tspan></text> - <path - inkscape:connector-curvature="0" - id="path4716" - d="M 269.71073,191.71224 791.91605,462.45778" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4718)" - 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="611.58893" - y="349.7601" - id="text5130" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5132" - x="611.58893" - y="349.7601">distance</tspan></text> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path5830" - d="m 258.28216,197.42653 0,113.16557" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 3;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker5832)" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 3;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker6528)" - d="m 258.28216,311.71224 228.57143,-2.54872" - id="path6526" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path7468" - d="M 280.42502,182.42653 496.85359,297.02067" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:9, 3;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker7470)" /> - <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="400" - y="223.07649" - id="text7888" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7890" - x="400" - y="223.07649">F</tspan></text> - <text - sodipodi:linespacing="125%" - id="text7892" - y="266.64792" - x="202.85715" - 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="266.64792" - x="202.85715" - id="tspan7894" - sodipodi:role="line">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan7896">y</tspan></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="356.42859" - y="354.50507" - id="text7898" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7900" - x="356.42859" - y="354.50507">F<tspan - id="tspan7902" - style="font-size:64.99999762%;baseline-shift:sub">x</tspan></tspan></text> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/net-force.png b/labs/lab4-barnes-hut-simulation/net-force.png deleted file mode 100644 index 0a24549d568fe8cdb5168bbf74dc03db5a41ded6..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/net-force.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/net-force.svg b/labs/lab4-barnes-hut-simulation/net-force.svg deleted file mode 100644 index 49e716b6bed3eb6b3ba4f656289e2e2ac2896549..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/net-force.svg +++ /dev/null @@ -1,327 +0,0 @@ -<?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="net-force.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\net-force.png" - inkscape:export-xdpi="44.869999" - inkscape:export-ydpi="44.869999"> - <defs - id="defs4"> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4222" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,0)" - style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:0.50289019;fill:#000000;fill-opacity:0.50289019" - 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="path4224" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4214" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path4216" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4208" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path4210" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker12608" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path12610" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker11876" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path11878" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker10168" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path10170" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker7470" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path7472" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker4622" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4624" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4228" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4231" - 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.4) rotate(180) translate(10,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.7" - inkscape:cx="742.82023" - inkscape:cy="615.35072" - 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 - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path10486" - d="M 281.85359,190.99796 1066.8536,329.87782" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4142" - cx="269.28571" - cy="190.21935" - r="13.141105" /> - <circle - r="13.141105" - cy="332.01859" - cx="1071.6188" - id="circle4144" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="267.72015" - y="162.38808" - id="text4146" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4148" - x="267.72015" - y="162.38808">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4150">1</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4152" - y="360.44257" - x="1098.4303" - 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="360.44257" - x="1098.4303" - id="tspan4154" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4158">2</tspan></tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4622)" - d="m 259.71073,187.42653 257.14285,45.7963" - id="path4190" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path5830" - d="M 273.99645,200.28367 659.71073,696.30638" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;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="724.85712" - y="443.07648" - id="text7888" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7890" - x="724.85712" - y="443.07648">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan10448">net</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text7892" - y="192.36221" - x="402.85715" - 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="192.36221" - x="402.85715" - id="tspan7894" - sodipodi:role="line">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan7896">21</tspan></tspan></text> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.83889103, 3.91944551;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker10168)" - d="M 271.13929,191.71224 699.0589,476.74351" - id="path10166" - 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="678.91986" - y="739.88269" - id="text10476" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan10478" - x="678.91986" - y="739.88269">m<tspan - id="tspan10480" - style="font-size:64.99999762%;baseline-shift:sub">3</tspan></tspan></text> - <circle - r="13.141105" - cy="704.74292" - cx="663.1554" - id="circle10482" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11876)" - d="M 268.28215,190.28367 449.0589,429.60064" - id="path11874" - inkscape:connector-curvature="0" /> - <text - sodipodi:linespacing="125%" - id="text13116" - y="268.07651" - x="245.71429" - 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="268.07651" - x="245.71429" - id="tspan13118" - sodipodi:role="line">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan13120">31</tspan></tspan></text> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/observation.png b/labs/lab4-barnes-hut-simulation/observation.png deleted file mode 100644 index 722840d6db1e3cd4821265e9b05f781fc600ce25..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/observation.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/observation.svg b/labs/lab4-barnes-hut-simulation/observation.svg deleted file mode 100644 index b41f92d7936430e19f2daf1f4d0b4e24d9b89d28..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/observation.svg +++ /dev/null @@ -1,407 +0,0 @@ -<?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="observation.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\observation.png" - inkscape:export-xdpi="44.869999" - inkscape:export-ydpi="44.869999"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker12608" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path12610" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker11876" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path11878" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker10168" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path10170" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker7470" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path7472" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker4718" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend" - inkscape:collect="always"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path4720" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker4622" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4624" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4228" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4231" - 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.4) rotate(180) translate(10,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.7" - inkscape:cx="557.69109" - inkscape:cy="615.35072" - 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 /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Layer 1" - inkscape:groupmode="layer" - id="layer1"> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4142" - cx="269.28571" - cy="190.21935" - r="13.141105" /> - <circle - r="13.141105" - cy="332.01859" - cx="1071.6188" - id="circle4144" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="267.72015" - y="162.38808" - id="text4146" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4148" - x="267.72015" - y="162.38808">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4150">1</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4152" - y="360.44257" - x="1098.4303" - 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="360.44257" - x="1098.4303" - id="tspan4154" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4158">2</tspan></tspan></text> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4622)" - d="m 259.71073,187.42653 152.85714,25.7963" - id="path4190" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - inkscape:connector-curvature="0" - id="path4716" - d="M 262.56786,184.56938 390.48747,293.88635" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4718)" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path5830" - d="M 273.99645,200.28367 659.71073,696.30638" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path7468" - d="M 277.56788,196.71225 898.28217,742.73496" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;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="677.71429" - y="470.21933" - id="text7888" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7890" - x="677.71429" - y="470.21933">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan10448">net</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text7892" - y="192.36221" - x="402.85715" - 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="192.36221" - x="402.85715" - id="tspan7894" - sodipodi:role="line">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan7896">21</tspan></tspan></text> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle8064" - cx="898.1554" - cy="741.17151" - r="13.141105" /> - <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="914.96698" - y="778.88129" - id="text8066" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan8068" - x="914.96698" - y="778.88129">m<tspan - id="tspan8070" - style="font-size:64.99999762%;baseline-shift:sub">3</tspan></tspan></text> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:7.83889103, 3.91944551;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker10168)" - d="M 271.13929,191.71224 661.91604,423.88636" - id="path10166" - 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="335.71429" - y="329.50507" - id="text10450" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan10452" - x="335.71429" - y="329.50507">F<tspan - id="tspan10454" - style="font-size:64.99999762%;baseline-shift:sub">31</tspan></tspan></text> - <circle - r="13.141105" - cy="497.88727" - cx="1058.5369" - id="circle10468" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <text - sodipodi:linespacing="125%" - id="text10470" - y="527.02557" - x="1083.2056" - 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="527.02557" - x="1083.2056" - id="tspan10472" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan10474">4</tspan></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="678.91986" - y="739.88269" - id="text10476" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan10478" - x="678.91986" - y="739.88269">m<tspan - id="tspan10480" - style="font-size:64.99999762%;baseline-shift:sub">5</tspan></tspan></text> - <circle - r="13.141105" - cy="704.74292" - cx="663.1554" - id="circle10482" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;stroke-opacity:1" - d="M 281.85359,190.99796 1056.8536,497.02068" - id="path10484" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path10486" - d="M 281.85359,190.99796 1066.8536,329.87782" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3,24;stroke-dashoffset:0;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11876)" - d="m 268.28215,190.28367 59.34818,80.74554" - id="path11874" - inkscape:connector-curvature="0" /> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:3.91944551;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker12608)" - d="M 266.85357,188.85509 493.34462,276.7435" - id="path12606" - 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="498.57144" - y="269.50507" - id="text13110" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan13112" - x="498.57144" - y="269.50507">F<tspan - id="tspan13114" - style="font-size:64.99999762%;baseline-shift:sub">41</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text13116" - y="268.07651" - x="245.71429" - 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="268.07651" - x="245.71429" - id="tspan13118" - sodipodi:role="line">F<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan13120">51</tspan></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="991.77698" - y="642.73987" - id="text13406" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan13408" - x="991.77698" - y="642.73987">M<tspan - id="tspan13410" - style="font-size:64.99999762%;baseline-shift:sub" /></tspan></text> - <circle - r="24.149361" - cy="598.31439" - cx="961.01251" - id="circle13404" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:10, 5;stroke-dashoffset:0;stroke-opacity:1" /> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/quadtree.png b/labs/lab4-barnes-hut-simulation/quadtree.png deleted file mode 100644 index 6db7c2139831b26340ee4480912c61de70f1d379..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/quadtree.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/quadtree.svg b/labs/lab4-barnes-hut-simulation/quadtree.svg deleted file mode 100644 index e36aff055bc0fb5f3c4599a855e54d814e72b296..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/quadtree.svg +++ /dev/null @@ -1,789 +0,0 @@ -<?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="quadtree.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\quadtree.png" - inkscape:export-xdpi="32.65155" - inkscape:export-ydpi="32.65155"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15906" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path15908" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker15660" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend" - inkscape:collect="always"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path15662" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker15306" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path15308" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15086" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path15088" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="marker15028" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path15030" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker12608" - style="overflow:visible;" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path12610" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker11876" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path11878" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="marker10168" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path10170" - 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.4) rotate(180) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible;" - id="marker7470" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mend"> - <path - transform="scale(0.4) rotate(180) translate(10,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="path7472" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4228" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Mend" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mend" - style="overflow:visible;" - inkscape:isstock="true"> - <path - id="path4231" - 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.4) rotate(180) translate(10,0)" /> - </marker> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.175" - inkscape:cx="1095.4717" - inkscape:cy="135.41975" - 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"> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4142" - cx="83.397331" - cy="151.83354" - r="13.141105" /> - <circle - r="13.141105" - cy="721.93744" - cx="1136.2686" - id="circle4144" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="-17.160173" - y="189.79347" - id="text4146" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4148" - x="-17.160173" - y="189.79347">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4150">A</tspan></tspan></text> - <text - sodipodi:linespacing="125%" - id="text4152" - y="748.34113" - x="1165.1003" - 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="748.34113" - x="1165.1003" - id="tspan4154" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan4158">E</tspan></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="1152.1206" - y="688.21014" - id="text7888" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan7890" - x="1152.1206" - y="688.21014">(x<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14976">E</tspan>,y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14974">E</tspan>)</tspan></text> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle8064" - cx="1028.7399" - cy="1033.1528" - r="13.141105" /> - <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="1045.5515" - y="1070.8625" - id="text8066" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan8068" - x="1045.5515" - y="1070.8625">m<tspan - id="tspan8070" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan></tspan></text> - <circle - r="13.141105" - cy="653.45074" - cx="741.34894" - id="circle10468" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <text - sodipodi:linespacing="125%" - id="text10470" - y="682.58905" - x="766.01764" - 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="682.58905" - x="766.01764" - id="tspan10472" - sodipodi:role="line">m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan10474">D</tspan></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="743.56964" - y="1123.7406" - id="text10476" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan10478" - x="743.56964" - y="1123.7406">m<tspan - id="tspan10480" - style="font-size:64.99999762%;baseline-shift:sub">B</tspan></tspan></text> - <circle - r="13.141105" - cy="1088.6008" - cx="727.80518" - id="circle10482" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;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="966.52319" - y="915.48102" - id="text13406" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan13408" - x="966.52319" - y="915.48102">mass</tspan></text> - <circle - r="24.149361" - cy="902.3703" - cx="916.56573" - id="circle13404" - style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:10, 5;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.00350261;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle14942" - cx="1019.0909" - cy="35.033726" - r="13.141105" /> - <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="1029.74" - y="8.9094801" - id="text14944" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan14946" - x="1029.74" - y="8.9094801">m<tspan - id="tspan14948" - style="font-size:64.99999762%;baseline-shift:sub">F</tspan></tspan></text> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect14952" - width="1052.579" - height="1052.579" - x="82.832512" - y="36.148746" /> - <rect - y="558.17084" - x="604.85461" - height="531.79376" - width="531.79376" - id="rect14954" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect14956" - width="521.14429" - height="521.14429" - x="84.185783" - y="37.502014" /> - <rect - y="-822.98016" - x="-869.66394" - height="264.46457" - width="264.46457" - id="rect14958" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - transform="scale(-1,-1)" /> - <rect - transform="scale(-1,-1)" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect14960" - width="265.25757" - height="265.25757" - x="-1134.2817" - y="-1087.5979" /> - <text - sodipodi:linespacing="125%" - id="text14978" - y="619.51978" - x="717.755" - 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="619.51978" - x="717.755" - id="tspan14980" - sodipodi:role="line">(x<tspan - id="tspan14982" - style="font-size:64.99999762%;baseline-shift:sub">D</tspan>,y<tspan - id="tspan14984" - style="font-size:64.99999762%;baseline-shift:sub">D</tspan>)</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="704.62305" - y="1058.9362" - id="text14986" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan14988" - x="704.62305" - y="1058.9362">(x<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14990">B</tspan>,y<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan14992">B</tspan>)</tspan></text> - <text - sodipodi:linespacing="125%" - id="text14994" - y="1004.3879" - x="991.50635" - 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="1004.3879" - x="991.50635" - id="tspan14996" - sodipodi:role="line">(x<tspan - id="tspan14998" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan>,y<tspan - id="tspan15000" - style="font-size:64.99999762%;baseline-shift:sub">C</tspan>)</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:100%;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="888.2475" - y="861.99701" - id="text15002" - sodipodi:linespacing="100%" - inkscape:export-xdpi="34.630001" - inkscape:export-ydpi="34.630001"><tspan - sodipodi:role="line" - id="tspan15004" - x="888.2475" - y="861.99701" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30px;line-height:100%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">(mass<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15020">X</tspan>,mass<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15016">Y</tspan>)</tspan></text> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path15022" - cx="-218.31874" - cy="1531.9603" - r="74.751289" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4.89491892;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker15028);marker-end:url(#marker15086)" - d="m 611.75315,1157.4181 516.98645,0" - id="path15026" - 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="825.29462" - y="1220.0476" - id="text15252" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan15254" - x="825.29462" - y="1220.0476">size<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan15256">SE</tspan></tspan></text> - <circle - r="74.751289" - cy="1300.5319" - cx="301.68127" - id="circle15266" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - r="74.751289" - cy="1531.9603" - cx="130.25279" - id="circle15268" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - r="74.751289" - cy="1531.9603" - cx="495.96689" - id="circle15270" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle15272" - cx="861.68121" - cy="1531.9603" - r="74.751289" /> - <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="253.18787" - y="1313.6995" - id="text15274" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan15276" - x="253.18787" - y="1313.6995">Fork</tspan></text> - <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;marker-end:url(#marker12608)" - d="m 229.18777,1310.8423 -392.8572,165.7143" - id="path15278" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - inkscape:connector-curvature="0" - id="path15304" - d="m 256.33057,1357.9852 -85.7143,108.5714" - 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;marker-end:url(#marker15306)" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path15658" - d="m 350.61637,1359.4137 104.2857,108.5715" - 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;marker-end:url(#marker15660)" /> - <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;marker-end:url(#marker15906)" - d="m 376.33067,1312.2709 425.7143,164.2857" - id="path15904" - inkscape:connector-curvature="0" - 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="20.037586" - y="1358.3875" - id="text16312" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16314" - x="20.037586" - y="1358.3875">nw</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="143.27599" - y="1409.9053" - id="text16316" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16318" - x="143.27599" - y="1409.9053">ne</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="412.98669" - y="1405.8646" - id="text16320" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16322" - x="412.98669" - y="1405.8646">sw</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="537.23566" - y="1364.4484" - id="text16324" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16326" - x="537.23566" - y="1364.4484">se</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16328" - y="1544.2709" - x="430.90222" - 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="1544.2709" - x="430.90222" - id="tspan16330" - sodipodi:role="line">Empty</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="97.928688" - y="1576.5566" - id="text16332" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16334" - x="97.928688" - y="1576.5566">F</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16342" - y="1574.5566" - x="-253.49989" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="1574.5566" - x="-253.49989" - id="tspan16344" - sodipodi:role="line">A</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16916" - y="1542.2709" - x="813.18781" - 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="1542.2709" - x="813.18781" - id="tspan16918" - sodipodi:role="line">Fork</tspan></text> - <circle - r="74.751289" - cy="1766.2461" - cx="338.8241" - id="circle16920" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle16922" - cx="687.39557" - cy="1766.2461" - r="74.751289" /> - <circle - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle16924" - cx="1053.1097" - cy="1766.2461" - r="74.751289" /> - <circle - r="74.751289" - cy="1766.2461" - cx="1418.8241" - id="circle16926" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path16928" - d="m 786.33067,1545.128 -392.8572,165.7143" - 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;marker-end:url(#marker12608)" /> - <path - sodipodi:nodetypes="cc" - 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;marker-end:url(#marker15306)" - d="m 813.47347,1592.2709 -85.7143,108.5714" - id="path16930" - 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;marker-end:url(#marker15660)" - d="m 907.75927,1593.6994 104.28563,108.5715" - id="path16932" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - inkscape:connector-curvature="0" - id="path16934" - d="m 933.47357,1546.5566 425.71423,164.2857" - 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;marker-end:url(#marker15906)" /> - <text - sodipodi:linespacing="125%" - id="text16936" - y="1584.1017" - x="605.75201" - 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="1584.1017" - x="605.75201" - id="tspan16938" - sodipodi:role="line">nw</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16940" - y="1644.1909" - x="700.41876" - 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="1644.1909" - x="700.41876" - id="tspan16942" - sodipodi:role="line">ne</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16944" - y="1640.1503" - x="970.12946" - 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="1640.1503" - x="970.12946" - id="tspan16946" - sodipodi:role="line">sw</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16948" - y="1598.7341" - x="1094.3785" - 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="1598.7341" - x="1094.3785" - id="tspan16950" - sodipodi:role="line">se</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16956" - y="1810.8424" - x="655.07159" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="1810.8424" - x="655.07159" - id="tspan16958" - sodipodi:role="line">E</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="303.64294" - y="1808.8424" - id="text16960" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16962" - x="303.64294" - y="1808.8424">D</tspan></text> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="1383.6429" - y="1807.9852" - id="text16968" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16970" - x="1383.6429" - y="1807.9852">C</tspan></text> - <text - sodipodi:linespacing="125%" - id="text16972" - y="1808.8424" - x="1017.9285" - style="font-style:normal;font-weight:normal;font-size:111.40943146px;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="1808.8424" - x="1017.9285" - id="tspan16974" - sodipodi:role="line">B</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="918.23126" - y="1466.4738" - id="text16976" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan16978" - x="918.23126" - y="1466.4738">mass = m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan16980">D</tspan> + m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan16982">E</tspan> + m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan16984">B</tspan> + m<tspan - style="font-size:64.99999762%;baseline-shift:sub" - id="tspan16986">C</tspan></tspan></text> - </g> -</svg> diff --git a/labs/lab4-barnes-hut-simulation/sectormatrix.png b/labs/lab4-barnes-hut-simulation/sectormatrix.png deleted file mode 100644 index 3d95d1fe934fd00122e95803dc3e2fa6a1789feb..0000000000000000000000000000000000000000 Binary files a/labs/lab4-barnes-hut-simulation/sectormatrix.png and /dev/null differ diff --git a/labs/lab4-barnes-hut-simulation/sectormatrix.svg b/labs/lab4-barnes-hut-simulation/sectormatrix.svg deleted file mode 100644 index e9c18380570ae70575c148b07bddf03cc51c82cd..0000000000000000000000000000000000000000 --- a/labs/lab4-barnes-hut-simulation/sectormatrix.svg +++ /dev/null @@ -1,477 +0,0 @@ -<?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="sectormatrix.svg" - inkscape:export-filename="C:\cygwin\home\axel22\workspaces\scala\parprog\statements\barneshut\sectormatrix.png" - inkscape:export-xdpi="32.6516" - inkscape:export-ydpi="32.6516"> - <defs - id="defs4"> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="marker4830" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4832" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:isstock="true" - style="overflow:visible" - id="marker4542" - refX="0.0" - refY="0.0" - orient="auto" - inkscape:stockid="Arrow1Mstart" - inkscape:collect="always"> - <path - transform="scale(0.4) translate(10,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="path4544" /> - </marker> - <marker - inkscape:stockid="Arrow1Mstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Mstart" - style="overflow:visible" - inkscape:isstock="true" - inkscape:collect="always"> - <path - id="path4196" - 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.4) translate(10,0)" /> - </marker> - <marker - inkscape:stockid="Arrow1Sstart" - orient="auto" - refY="0.0" - refX="0.0" - id="Arrow1Sstart" - style="overflow:visible" - inkscape:isstock="true"> - <path - id="path4202" - 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.2) translate(6,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="692.30131" - inkscape:cy="448.67197" - 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"> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4138" - width="157.25688" - height="157.25688" - x="160.41716" - y="293.24829" /> - <rect - y="293.24829" - x="317.80426" - height="157.25688" - width="157.25688" - id="rect4140" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="293.24829" - x="474.40179" - height="157.25688" - width="157.25688" - id="rect4142" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4144" - width="157.25688" - height="157.25688" - x="631.78894" - y="293.24829" /> - <rect - y="450.89859" - x="160.41716" - height="157.25688" - width="157.25688" - id="rect4146" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4148" - width="157.25688" - height="157.25688" - x="317.80426" - y="450.89859" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4150" - width="157.25688" - height="157.25688" - x="474.40179" - y="450.89859" /> - <rect - y="450.89859" - x="631.78894" - height="157.25688" - width="157.25688" - id="rect4152" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="608.02252" - x="160.41716" - height="157.25688" - width="157.25688" - id="rect4154" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4156" - width="157.25688" - height="157.25688" - x="317.80426" - y="608.02252" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4158" - width="157.25688" - height="157.25688" - x="474.40179" - y="608.02252" /> - <rect - y="608.02252" - x="631.78894" - height="157.25688" - width="157.25688" - id="rect4160" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4162" - width="157.25688" - height="157.25688" - x="160.41716" - y="765.67279" /> - <rect - y="765.67279" - x="317.80426" - height="157.25688" - width="157.25688" - id="rect4164" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - y="765.67279" - x="474.40179" - height="157.25688" - width="157.25688" - id="rect4166" - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <rect - style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:4.60580969;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect4168" - width="157.25688" - height="157.25688" - x="631.78894" - y="765.67279" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="path4170" - cx="435" - cy="491.64792" - r="13.571428" /> - <circle - r="13.571428" - cy="854.50507" - cx="699.28577" - id="circle4172" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4174" - cx="769.28577" - cy="824.50507" - r="13.571428" /> - <circle - r="13.571428" - cy="894.50507" - cx="790.71436" - id="circle4176" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4178" - cx="726.42865" - cy="295.93362" - r="13.571428" /> - <circle - r="13.571428" - cy="805.93365" - cx="267.85727" - id="circle4180" - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <circle - style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="circle4182" - cx="555.20319" - cy="717.37964" - r="13.571428" /> - <path - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;marker-start:url(#Arrow1Mstart)" - d="m 721.42857,569.50506 c 250,-70 350.00003,-5.71428 350.00003,-5.71428" - id="path4184" - 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="1090" - y="582.36218" - id="text4530" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4532" - x="1090" - y="582.36218" - style="-inkscape-font-specification:'Andale Mono';font-family:'Andale Mono';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">ConcBuffer[Body]</tspan></text> - <path - inkscape:connector-curvature="0" - id="path4540" - d="m 738.57143,392.3622 c 250,-70 395.71437,142.85715 395.71437,142.85715" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4542)" - sodipodi:nodetypes="cc" /> - <path - sodipodi:nodetypes="cc" - style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:15, 5;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker4830)" - d="m 725.71429,699.50506 c 280.00001,38.57143 402.85731,-92.85714 402.85731,-92.85714" - id="path4828" - 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="171.72594" - y="345.25543" - id="text5218" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5220" - x="171.72594" - y="345.25543">0,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5222" - y="345.25543" - x="341.43158" - 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="345.25543" - x="341.43158" - id="tspan5224" - sodipodi:role="line">1,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="494.97476" - y="345.25543" - id="text5226" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5228" - x="494.97476" - y="345.25543">2,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5230" - y="345.25543" - x="650.53827" - 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="345.25543" - x="650.53827" - id="tspan5232" - sodipodi:role="line">3,0</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5234" - y="504.85953" - x="171.72594" - 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="504.85953" - x="171.72594" - id="tspan5236" - sodipodi:role="line">0,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="341.43158" - y="504.85953" - id="text5238" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5240" - x="341.43158" - y="504.85953">1,1</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5242" - y="504.85953" - x="494.97476" - 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="504.85953" - x="494.97476" - id="tspan5244" - sodipodi:role="line">2,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="650.53827" - y="504.85953" - id="text5246" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5248" - x="650.53827" - y="504.85953">3,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="171.72594" - y="656.38239" - id="text5250" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5252" - x="171.72594" - y="656.38239">0,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5254" - y="656.38239" - x="341.43158" - 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="656.38239" - x="341.43158" - id="tspan5256" - sodipodi:role="line">1,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="494.97476" - y="656.38239" - id="text5258" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5260" - x="494.97476" - y="656.38239">2,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5262" - y="656.38239" - x="650.53827" - 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="656.38239" - x="650.53827" - id="tspan5264" - sodipodi:role="line">3,2</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5266" - y="813.96619" - x="171.72594" - 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="813.96619" - x="171.72594" - id="tspan5268" - sodipodi:role="line">0,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="341.43158" - y="813.96619" - id="text5270" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5272" - x="341.43158" - y="813.96619">1,3</tspan></text> - <text - sodipodi:linespacing="125%" - id="text5274" - y="813.96619" - x="494.97476" - 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="813.96619" - x="494.97476" - id="tspan5276" - sodipodi:role="line">2,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="650.53827" - y="813.96619" - id="text5278" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan5280" - x="650.53827" - y="813.96619">3,3</tspan></text> - </g> -</svg> diff --git a/labs/lab5-bounded-buffer/README.md b/labs/lab5-bounded-buffer/README.md deleted file mode 100644 index e725d0fd397a01ee056ad03ea94206c4902084e3..0000000000000000000000000000000000000000 --- a/labs/lab5-bounded-buffer/README.md +++ /dev/null @@ -1,260 +0,0 @@ -# Concurrent Bounded Buffer - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b pubsub git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-pubsub -``` - -## Useful links - - * [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 - -The goal of this assignment is to implement a fixed size buffer that can be accessed concurrently by multiple threads running in parallel. -This is a simple yet important data structure that is widely used in concurrent applications. -In particular, we provide you an implementation of a Publish/Subscribe (PubSub) application that uses the bounded buffer you would be developing. -We will provide a brief overview of the Publish/Subscribe application, and instructions on how to run it towards the end of this assignment. -However, the only data structure that you should implement for this assignment is the bounded buffer, which is explained below. - -## Bounded Buffer - Definition and Operations - -A concurrent bounded buffer is a data structure that supports the following two operations: -- a method `put(e)` that puts a value `e` in the buffer, -- a method `take` that takes a value from the buffer, and removes it. - -Importantly, the `put` and `take` methods should follow the FIFO (First-In, First-Out) semantics. -Intuitively, this means that `take` should return the _oldest_ element that was `put` into the buffer. -<!-- [comment]: # (A pointer to linearizability ?) --> - -The buffer is *bounded*, which means that it can only store a finite number of elements. -The maximum number of elements the buffer can hold is passed as an argument to the constructor of `BoundedBuffer`. -The following is the definition of the data structure, which can be found in the file: -`src/main/scala/pubsub/collection/BoundedBuffer` - -```scala -class BoundedBuffer[T](size: Int) extends AbstractBoundedBuffer[T](size): - override def put(e: T): Unit = ??? - override def take(): T = ??? -``` - -A `put` operation invoked on a buffer that is full will *wait* (or block) until an element is taken from -the buffer. Dually, a `take` operation invoked on an empty buffer will *wait* until an element is put -into the buffer. -Note that multiple `put` and `take` operations can be initiated concurrently from different threads. Hence, -care must be taken to ensure that the `buffer` is not accessed or left in an inconsistent state by the `put` or `take` -methods. To understand the challenges better let us start by considering a sequential setting. - -## A Sequential Bounded Buffer - -Let us try to implement the `BoundedBuffer` class without worrying at all about concurrency. -That is, imagine that there is only one thread that performs a sequence of `put` and `take` operations on an object of type `BoundedBuffer`. -Can you implement the `put` and `take` methods in this setting? -Note that your implementation should run in constant time in the worst-case. -(A remark: the data structure you implement in this case is also called a _circular queue_.) - -To write your solution, use the `pubsub.collection.BoundedBuffer` class skeleton that is given to you in the handout. -You are given two _variables_: `count` and `head`, and an internal buffer that exposes a minimal array-like API. -It is important that you use the variables given to you, and the internal buffer API. -*You are strongly advised not to create any other fields or classes or objects*. Otherwise, -you may fail the testcases. - -The following is an illustration of the input/output behavior of the buffer in the sequential case. -In the comments, we show the contents of the array used internally by the `BoundedBuffer` class, and the -return values (if any) of the operations. - -```scala -def example1() = // Internal Buffer: - val buf = new BoundedBuffer(2) // | | | - buf.put(1) // | 1 | | - buf.put(2) // | 1 | 2 | - val x = buf.take() // | | 2 | and x is 1 - buf.put(3) // | 3 | 2 | - val y = buf.take() // | 3 | | and y is 2 -``` - -Now, think about what should happen if we try to `put` an element into a buffer that is full? -Obviously, the element cannot be stored in the buffer. Furthermore, there is no use of waiting for -some space to be created in the buffer because no element in the buffer could be read simultaneously. -(Recall that there is only one thread accessing the buffer in the sequential setting). -Hence, you may throw an exception in this case. Similarly, handle the dual case of invoking a -`take` on an empty buffer. - -Think about what happens when your sequential buffer is used in a concurrent system. What can happen? -Try running the test suite that was given to you with the handout. What can you see? - -As you may have seen, the test suite was able to find many problematic schedules for the non-concurrent buffer. This is to be expected! -Now, using your sequential implementation as a stepping stone, let us develop a concurrent bounded buffer, which is your real goal. - -## Concurrent Bounded Buffer - -Now, let us imagine that there are two threads currently performing operations on a shared buffer of -max size 2 as shown below: - -```scala -val buf = new BoundedBuffer(2) - Thread 1 Thread 2 - buf.put(1) y = buf.take() -``` - -The first change you need to make to your sequential implementation is that `buf.take()` invoked -by `Thread 2` should *wait* until an element is put into the buffer by `Thread 1`. -Similarly, a `put` method should *wait* until an element is taken from the buffer. -Throwing an exception in these cases as in the sequential case is not acceptable -here because operations can be happening simultaneously. In other words, a `put` that cannot -succeed now can succeed in the future, because of a concurrently executing `take`. - -For this purpose, you may use a `wait` method of the Java standard library. -You can find a brief description of the semantics of the method, and references for further reading in the section *Synchronization Primitives* below. An alternative is to loop continuously until the buffer has an element. This is called as *busy waiting*. But as you can imagine this wastes precious processor cycles, and hence is not preferred. (See the section on busy waiting as well for some examples.) - -With this waiting strategy, in the above example, `Thread 2` will enter into *wait* state if it executes before `Thread 1`, -and `Thread 1` will proceed to execute. However, after completing the execution `Thead 1` should *wake up* -`Thread 2` (and also every other thread that would be waiting on the buffer to become non-empty). -For this purpose, you have to use the `notify()`, and/or `notifyAll()` primitives (see section *Synchronization Primitives*). -Note that there are subtle differences between `notify()` and `notifyAll()` which is also briefly explained below. - -*Important Hint: You should invoke the synchronization primitives like `wait`, `notify`, `synchronized` etc. only -on the `this` reference when implementing the methods of the `BoundedBuffer` class. Otherwise, your -implementation may get stuck (and run into deadlocks) while testing* - -Also remember that `notify` and `wait` should be invoked only inside a `synchronized` block. - -Now that we know how to implement the waiting strategy to alleviate the above problem of `Thread 2` -running before `Thread 1`, let us look at other issues that may arise when `put` and `take` methods run concurrently. -In particular, say `Thread 1` starts before `Thread 2`. -Let us study how the operations they perform can interleave, assuming that you implemented -them using `count` and `head`. -Consider the following interleaving of operations of `put` and `get` - -```scala -val buf = new BoundedBuffer(2) - Thread 1 Thread 2 - //start buf.put(1) - //start buf.take - //reads count -> 0 - //... - //updates count -> 1 - //reads count -> 1 - //read internal buffer(0) (crash !!) - //internal buffer(0) <- 1 -``` - -Clearly, if your code permits the above interleaving then it would crash. Now, your goal is to come up -with adequate synchronization so that no interleaving of operations of `put` and `take` performed -by any number of threads result either in a crash or in an incorrect buffer state. -You may use all the synchronization primitives described below. - -The test suite provided along with the project may help you find problematic schedules. -A schedule is a sequence of operations carried out by the different threads such as the one -shown above. -The test suite runs your code on several thousand schedules. You may use that to check whether your bounded -buffer reaches a consistent state on some schedule. - -An incorrect run on a schedule could either be that: -- An operation returns an incorrect value. -- An operation throws an exception when it should not. - -Remember that some operations, even though they look *atomic*, are decomposed into multiple smaller operations. -For instance, consider `buffer(head) = ...`. Is this atomic ? -In the remaining sections, we talk about the synchronization primitives and some of the commons cases of errors. - -## Synchronization Primitives - -- `synchronized[T](body: => T)`, which executes `body` in a critical section. This ensures that only a single thread at a time can execute the instructions passed as argument. -- [`wait()`][1], which stops the execution of the thread until it is notified. `wait()` can only be called within a `synchronized` block. -- [`notify()`][2], which unblocks one of the waiting thread. Note that it's not possible to specify which thread is unblocked. -- [`notifyAll()`][3], which unblocks all of the waiting threads. - -## Using the Pub/Sub Server -The following section describes how you can run and use the Pub/Sub server implemented for you, -This small server allows any amount of people to connect and chat together around topics of their choice. Playing with it may help you discover errors in your ConcurrentBoundedBuffer. - -### Running the server -You can start the Pub/Sub Server as any normal SBT project, simply type `sbt run` while in the root folder of the project. No additional setup is required. - -### Connecting to the server -You can connect to the server via command-line interface and the [`telnet`][4] protocole. -When the server is started it will display a line such as: - - Connect to <server_ip> (or `localhost`), port 7676 with `telnet` to join this server -Which gives you the IP address of the running server. -In your command-line you must do the following telnet command: `telnet <server_ip> 7676` -You should then be greeted by the server with a `connection_ack`. - -*telnet is not enabled by default on Windows 8 and 10; [here are fast and simple instructions to enable telnet on recent Windows][5]* - -*There are also issues with telnet connecting to the server when using Windows 10 due to firewall issues. However on Linux telnet works flawlessy [sorry for any inconvenience]* - -### Commands available -Now that the server is running and you have a connected client, here is the comprehensive list of the commands any client can use on the server: - -- `rename <nickname>`: change your display name to `<nickname>`. Your new name cannot contain any space or single quote. -- `subscribe <topic>`: add yourself to the `<topic>` subscriber list. You will receive all messages sent to that topic. -- `unsubscribe <topic>`: remove yourself from the `<topic>` subscriber list. You will no longer receive messages sent to that topic. -- `publish <topic> '<message>'`: publish the `<message>` of your choice to the `<topic>` of your choice. Your `<message>` can span on multiple lines but has to be enclosed with single-quote `'` to be deemed valid. -- `leave`: end the connection with the server in a polite manner - - -## Common Pitfalls - -### Busy Waiting - -Consider the following code snippet that uses a while loop (with an empty body) to guard the execution of the `put` and `take` operations. - -```scala -class BoundedBuffer[T](size: Int) extends AbstractBoundedBuffer[T](size): - override def put(e: T): Unit = - while isEmpty do () - // Rest of your code - ??? - override def take(): T = - while isEmpty do () - // Rest of your code - ??? -``` - -What is the problem with this way of waiting? Apart from those potential problems, -is this code behaving correctly in a concurrent setting i.e, is there a schedule that would -result in an incorrect behavior on the above code. -_Hint: what happens when one `put` and two `take` are running in parallel ?_ - -### `notify()` vs `notifyAll()` - -As per the documentation [documentation][2]:_ of `notify()`, invoking the `notify` method on an object `o` wakes up a _single_ thread that is waiting on the object `o`'s monitor. If there are multiple threads waiting on `o`, one of them is chosen **arbitrarily** at the discretion of the implementation. Note that a thread waits on an object's monitor by calling one of the wait methods. - -Using the `notify` method often leads to tricky problems which can sometimes result in deadlocks. This can lead to bugs that can be hard to see and reproduce. For this reason, it is often strongly advised to use `notifyAll` instead. -Can you figure out why this is the case? -_Hint: Could it ever happen that the thread unblocked by notify somehow cannot execute even though there are other threads that could execute if they were unblocked instead ?_ - -### Waiting using `if` vs `while` - -Due to the semantics of `notify` and `notifyAll`, there are no guarantees that the condition on which a thread is waiting will be fulfilled when the thread is unblocked. Therefore, the following code is problematic: - -```scala -synchronized { - if !condition then - wait() - // We have no garantees that the condition holds here. -} -``` - -Instead, the waiting thread should always recheck the condition when it is unblocked. This can easily be done using a `while` instead of `if`. - -Can you come up with a schedule in which using a simple `if` would be problematic? - -_Hint: Try using a system with 3 threads, two of which try to execute `take` and one of which executes `put` in an initially empty buffer?_ - -_Hint: Note that, as specified in the [documentation of `notify`][2]:_ -> The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, **the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object**. - -[1]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#wait() -[2]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#notify() -[3]: https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#notifyAll() -[4]: https://en.wikipedia.org/wiki/Telnet -[5]: http://www.sysprobs.com/install-and-enable-telnet-in-windows-8-use-as-telnet-client diff --git a/labs/lab6-lock-free-sorted-list/README.md b/labs/lab6-lock-free-sorted-list/README.md deleted file mode 100644 index 43da43b33f7fb5f2cf97a8e3aaf665b1c4383dc9..0000000000000000000000000000000000000000 --- a/labs/lab6-lock-free-sorted-list/README.md +++ /dev/null @@ -1,196 +0,0 @@ -# Lock-free Sorted List - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b lockfree git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-lockfree -``` - -## Useful links - - * [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 - -The goal of this assignment is to implement a concurrent list that stores values of type `Int` in ascending order. -Last week, we have seen how to use a monitor to make data structures operations behave correctly in a concurrent setting. -This week, the data structure we will implement will not use a monitor or a lock of any kind. -Instead, we will use an atomic operation, called `compareAndSet`, in your implementation of the data structure operations. - -The goal will still be to have a data structure that can safely be used in a concurrent setting. -In addition, the sorted list operations you will implement will be *lock-free*. -In a system where all concurrent operations have this property, the progress of at least one thread is ***guaranteed***. -There can not be a global deadlock in which none of the thread can make progress! -Note that this does *not* guarantee that all threads can make progress. -Operation with this property is said to be *wait-free*. - -## Atomic Variables - -The list methods you will implement will make use of atomic variables. An atomic variable is an object which holds a value of a given type `T`. The object offers two methods to manipulate this value: -- `get`, which returns the current value held in the variable, -- `compareAndSet`, which modifies the content of the variable provided that the previous value is given. This method returns `true` if it was successful, `false` otherwise. - -The operation `compareAndSet` applies the following logic ***atomically***, which means there cannot be any context switches between the instructions of the operation: -```scala -def compareAndSet(expected: T, value: T): - if current == expected then - current = value - true - else - false -``` - -The `AtomicVariable` class is given to you. You do not have to worry about implementing it! - -Note that a similar class exists in the Java standard library, called [`AtomicReference`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html). -The main difference between `AtomicReference` and the `AtomicVariable` class we defined for this exercise is that `AtomicReference` uses referential equality to check whether `expected` and `current` are the same, while `AtomicVariable` uses the `==` method. - -## The Sorted List Data Structure - -The data structure you will implement is a mutable linked list of integers, sorted in ascending order. Each integer is stored in a `Node`. In addition to the integer value, each node contains a mutable reference to the next node in the list. This mutable reference is held in an `AtomicVariable`. - -```scala -abstract class Node(val value: Int, initTail: Option[Node]): - - type State = Option[Node] - - def initialState: State = initTail - - val atomicState: AbstractAtomicVariable[State] = new AtomicVariable[State](initialState) - - def next: Option[Node] = atomicState.get - - // ... -``` - -Then, `SortedList` is simply a class that holds a reference to the first node of the list. This class is defined in `SortedList.scala`. - -```scala -class SortedList extends AbstractSortedList: - - // The sentinel node at the head. - private val _head = createNode(0, None, isHead=true) - - // The first logical node is referenced by the head. - def firstNode: Option[Node] = _head.next - - def findNodeWithPrev(pred: Int => Boolean): (Node, Option[Node]) = ??? - - def insert(e: Int): Unit = ??? - - def contains(e: Int): Boolean = ??? - - def delete(e: Int): Boolean = ??? -``` - -The value `_head` of the list is called a [*sentinel* node](https://en.wikipedia.org/wiki/Sentinel_node). This value is simply a `Node` that will serve only as a reference to the first actual node of the list. The value (viz. zero) held by this special node should be completely ignored. This technique is useful because it limits the duplication of code. An alternative would be to have a reference to the first node using an `AtomicVariable`. But this would force us to handle the first node differently from the rest. So we will use a sentinel node for this assignment. - -### `findNodeWithPrev` - -The first method you will implement is an internal helper method which will be used by all other methods. -This method should do a traversal of the list to find the first node whose value satisfies the parameter predicate. -The method should return the following two values as a pair: -- the predecessor of the node, -- the node. - -If `node` is the first node whose value satisfies the predicate and `predecessor` its predecessor, then the method should return `(predecessor, Some(node))`. Due to the use of the sentinel node at the head of the list, the method is bound to find a predecessor, even for the first logical node. - -When the predicate doesn't hold on any of the values, then the function should return `(last, None)`, where -`last` is the last node of the list. - -### `insert` - -Your first goal will be to code the insert method of the lock-free list. The idea is to: - -1. Locate the position where you need to insert by using the `findNodeWithPrev` method you have just implemented. -2. Create a new node that holds the value and points to the correct next node. For this, you should use `createNode(value, nextNode)`. -3. Use the `compareAndSet` operation to make the previous node point to your newly created node. -4. If the operation failed, retry from the start! Otherwise, the operation is done! - -### `contains` - -Next, you should implement the `contains` method, which checks if the list contains a given element. You may of course use the `findNodeWithPrev` method you have implemented. - -### `delete` - -With the addition of `delete`, things get rapidly trickier. The intuitive solution would be to: - -1. Find the node to delete and its predecessor using `findNodeWithPrev`. -2. Use an atomic `compareAndSet` operation to make the predecessor node point to the successor. - -Unfortunately, this solution is not entirely satisfactory! -Indeed, there exist schedules in which some successful operations are lost. Can you think of any? - -As an example, assume that the list currently contains the values `10` and `30`. - - - -- Imagine one thread starts executing the insertion of `20` in the list and correctly locates where to insert the new node (between `10` and `30`). The thread then creates a node with value `20` and makes it point to the node with value `30`. - -  - -- Now, some other thread is scheduled and starts executing the deletion of the node with value `10`. The thread finds the two nodes that surround it, that is the sentinel node at the head of the list and the node with value `30` (note that the insertion of `20` by the other thread isn't visible yet!). The thread, using compare and set, changes the next pointer of the sentinel node to the node with value `30`. The `delete` operation then terminates successfully. - -  - -- Now, the first thread resumes its execution. Its next instruction is to use compare and set to change the next pointer of the node with value `10`, which it can do without any problem! Indeed, this atomic variable wasn't touched by the delete operation. The `insert` operation looks successful, even though the node that was inserted is not reachable from the head of the list! The operation was lost... - -  - -One solution to this problem, as proposed by Timothy L. Harris in his paper [A Pragmatic Implementation of Non-Blocking Linked Lists](https://www.cl.cam.ac.uk/research/srg/netos/papers/2001-caslists.pdf), is to somehow record in the node that it was deleted. -We will proceed similarly in this assignment. - -#### Marking Nodes - -The first step is to modify the mutable state held by nodes. Open the `Node.scala` file. Until now the state was just `Option[Node]`, which is an optional reference to the next node. -You will need to add, in addition to this information, a boolean flag that indicates whether the node was deleted or not. - - -```scala -abstract class Node(val value: Int, initTail: Option[Node]): - - type State = ??? - - def initialState: State = ??? - - val atomicState: AbstractAtomicVariable[State] = new AtomicVariable[State](initialState) - - def next: Option[Node] = ??? - - def deleted: Boolean = ??? - - def mark: Boolean = ??? -``` - -Begin by modifying the `State` type to any type that you deem appropriate. Remember that the value of this type should contain an `Option[Node]` (the next node) and a flag (whether the node has been marked). - -Complete the other functions, described below, as well: -- `initialState` should return the state of the node when it is first created. Note that the node should not be marked and the optional reference to the next node should be set to `initTail`. -- `next` should return the optional reference to the next node held currently in the state. -- `deleted` should return `true` if the node was marked, `false` otherwise. -- `mark` should mark the node as `deleted`. The method should return `true` only if it is the first time this node is marked. If the node was previously marked, this method should return `false`. (Think carefully about this!) - -#### Implementing `delete` of `SortedList` - -Now, we can implement a version of delete that is not vulnerable to the problem exposed earlier. The idea is to: - -1. Find the node to delete and its predecessor using `findNodeWithPrev`. -2. Mark the node as `deleted` using its `mark` method. If it returns false, retry from the start! - -Once this is done, we still have to modify the other list methods to handle the fact that nodes can be marked. -Marked nodes will be deleted within the `findNodeWithPrev` method. - -#### Adapting `findNodeWithPrev` to handle marked nodes - -The first method you need to adapt is `findNodeWithPrev`. The method should do exactly as before except when it encounters a marked node during its traversal. When it does so, the method should use compare and set to modify the next node pointed by the predecessor node. Regardless of the outcome of the compare and set operation, the `findNodeWithPrev` should then restart from scratch. - -#### Adapting `insert` to handle marked nodes - -The last method you need to change is `insert`. The logic remains exactly the same, except that when you perform the `compareAndSet` operation, you should make sure that the parameters are of type `State` and are not flagged as deleted. - -You are now done with this assignment. Congratulations! diff --git a/labs/lab6-lock-free-sorted-list/step0.png b/labs/lab6-lock-free-sorted-list/step0.png deleted file mode 100644 index 7730e289490798d2a298b3794e592fd810a81df3..0000000000000000000000000000000000000000 Binary files a/labs/lab6-lock-free-sorted-list/step0.png and /dev/null differ diff --git a/labs/lab6-lock-free-sorted-list/step1.png b/labs/lab6-lock-free-sorted-list/step1.png deleted file mode 100644 index 59a5df13ab342a8965fff748ab716d17365d28b4..0000000000000000000000000000000000000000 Binary files a/labs/lab6-lock-free-sorted-list/step1.png and /dev/null differ diff --git a/labs/lab6-lock-free-sorted-list/step2.png b/labs/lab6-lock-free-sorted-list/step2.png deleted file mode 100644 index 1b09129d815cdbc2081ca7d9073c9c18cb6d0a90..0000000000000000000000000000000000000000 Binary files a/labs/lab6-lock-free-sorted-list/step2.png and /dev/null differ diff --git a/labs/lab6-lock-free-sorted-list/step3.png b/labs/lab6-lock-free-sorted-list/step3.png deleted file mode 100644 index fb9dcfff4ac0a5ecbe3cbee823a1793b03e7c0d9..0000000000000000000000000000000000000000 Binary files a/labs/lab6-lock-free-sorted-list/step3.png and /dev/null differ diff --git a/labs/lab7-hazard-pointer/hazardptr.md b/labs/lab7-hazard-pointer/hazardptr.md deleted file mode 100644 index 1ab89fc5f264e545decbc32e776ed979660f1fbd..0000000000000000000000000000000000000000 --- a/labs/lab7-hazard-pointer/hazardptr.md +++ /dev/null @@ -1,147 +0,0 @@ -# Sorted Doubly Linked-List - -The goal of this assignment is to implement a concurrent list that stores values of type `Int` in ascending order. Last week, we have seen lock-free list which uses Node marking to marks nodes to be deleted. The week, the list is a doubly linked list without any node marking. The data structure allows access to a single writer(Insert/Delete) but multiple readers can run concurrently. - -The goal will be to have a data structure that can safely allow readers to do the traversal even if writer has deleted the node. Hazard pointers will be used to achieve that. - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b hazardptr git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-hazardptr -``` - -## Hazard Pointer (https://ieeexplore.ieee.org/document/1291819) - -Hazard Pointer is a garbage collection technique which allows concurrent access to an object in a thread even when it might be deleted by other threads. For example, thread A might be deleting a node and at the same time another thread B can have access to that same node. If thread A frees the memory, then thread B will crash because it is trying to access invalid address. - -The sorted list methods you will implement will make use of hazard pointers. Hazard pointers are a per-thread pointers which are used to protect readers in case there is a concurrent delete of the same node. For the sorted list data structure, you will use two hazard pointers per thread. - -Whenever there is a delete operation, the node is added to the per-thread retireList. If the size of the retireList exceeds some threshold, then that thread will iterate over all per-thread hazard pointers to figure out which nodes are currently not in use and can be safely deleted. - -Following is the implementation of the AbstractHazardPointer class. - -```scala -abstract class AbstractHazardPointer(numPointerPerThread: Int) extends Monitor: - - val maxThreads = 10 - - val threshold = 2 - - val hazardPointerArray: ArrayBuffer[Option[Node]] = ArrayBuffer.fill(numPointerPerThread * maxThreads)(None) - - val retiredListArray: ArrayBuffer[ArrayBuffer[Option[Node]]] = ArrayBuffer.fill(maxThreads)(ArrayBuffer()) - - // This function will be overridden when running in parallel. - def getMyId(): Int = 0 - - // Update ith per-thread hazard pointer ( 0 <= i <= numPointerPerThread ) - def update(i: Int, n: Option[Node]): Unit - - // Return ith per-thread hazard pointer ( 0 <= i <= numPointerPerThread ) - def get(i: Int): Option[Node] - - def retireNode(node: Option[Node]) : Unit -``` - -hazardPointerArray is an Array of hazard pointers. This array will store per-thread hazard pointers. You can use `get` / `update` functions to read/write per-thread hazard pointers. - -You have to implement the retireNode function in the hazardPointer class. - -```scala -class HazardPointer(numPointerPerThread: Int) extends AbstractHazardPointer(numPointerPerThread): - - def retireNode(node: Option[Node]) = ??? -``` -### `retireNode` - -Implement the function to retire the node. The method should do the following : -- Add the node to thread's retired list. -- If the size of retired list is greater than a pre-defined threshold. Remove all the elements from the list which are not pointed by any hazard pointer of all the threads. - -## The Sorted List Data Structure - -The data structure you will implement is a mutable linked list of integers, sorted in ascending order. Each integer is stored in a `Node`. In addition to the integer value, each node contains a mutable reference to the next and previous node in the list. - -```scala -class Node(val value: Int, var next: Option[Node] = null, var prev: Option[Node] = null) { -} -``` - -Then, `SortedList` is simply a class that holds a reference to the first node of the list. This class is defined in `SortedList.scala`. - -```scala -class SortedList extends AbstractSortedList: - - - // The sentinel node at the head. - val _head: Option[Node] = Option(createNode(0, None, None, isHead = true)) - - // The first logical node is referenced by the head. - def firstNode: Option[Node] = _head.get.next - - val hazardPointers = new HazardPointer(2) - - // Finds the first node whose value satisfies the predicate. - // Returns the predecessor of the node and the node. - def findNodeWithPrev(pred: Int => Boolean): (Option[Node], Option[Node]) = ??? - - //Find Nth Node after current element. Return 0 if out of bounds. - def getNthNext(e: Int, n: Int): Int = ??? - - // Count occurrence of the element. - def countOccurrences(e: Int): Int = ??? - - // Insert an element in the list. - def insert(e: Int): Unit = synchronized { - ??? - } - - // Checks if the list contains an element. - def contains(e: Int): Boolean = ??? - - // Delete an element from the list. - // Should only delete one element when multiple occurrences are present. - def delete(e: Int): Boolean = synchronized { - ??? - } - - -``` - -The value `_head` of the list is called a [*sentinel* node](https://en.wikipedia.org/wiki/Sentinel_node). This value is simply `Node` that will serve only as a reference to the first actual node of the list. The value (viz. zero) held by this special node should be completely ignored. - -The data structure support single writer and multiple readers. Insert and Delete function acts as writing to the data structure and these should be executed one at a time, even though multiple threads are trying to insert/delete. Rest of the functions are reading the data structure and can be executed concurrently. Use hazard pointers in these function to protect against concurrent delete. - -### `findNodeWithPrev` - -The first method you will implement is an internal helper method which will be used all other methods. -This method should do a traversal of the list to find the first node whose value satisfies the parameter predicate. -The method should return the following two values as a pair: -- the predecessor of the node, -- the node. - -If `node` is the first node whose value satisfies the predicate and `predecessor` its predecessor, then the method should return `(predecessor, Some(node))`. Due to the use of the sentinel node at the head of the list, the method is bound to find a predecessor, even for the first logical node. There can also be concurrent insert/delete while traversal, so the method should also check if the next of the `predecessor` node points to `node` or not. If yes, then the method should return `(predecessor, Some(node))` or else start from the beginning. - -When the predicate doesn't hold on any of the values, then the function should return `(last, None)`, where -`last` is the last node of the list. - -Since the traveral is lock-free, the previous and current node should be protected by hazard pointers. - -### `insert` / `delete` - -Implement insert and delete into doubly linked list. You can use `findNodeWithPrev` function. - -### `contains` - -Next, you should implement the `contains` method, which checks if the list contains a given element. - -### `getNthNext` - -Implement a method which will find the first occurence of `e` and then return the value of the node which is Nth next from that node. For example, if we have a list 1->2->3->4->5, element to search(e) = 3 and N=2. Then Nth next is 5. - -### `countOccurrences` - -Finally, implement a method which count occurences of the element in the list. - -You are now done with this assignment. Congratulations! - diff --git a/labs/lab8-actors-binary-tree/README.md b/labs/lab8-actors-binary-tree/README.md deleted file mode 100644 index b33e9a0a93ff6b1b161d560973cad4e1716bdf6e..0000000000000000000000000000000000000000 --- a/labs/lab8-actors-binary-tree/README.md +++ /dev/null @@ -1,162 +0,0 @@ -# Binary Trees - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b actorbintree git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-actorbintree -``` - -## Useful links - - * [The API documentation of Akka](https://doc.akka.io/api/akka/current/akka/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 - -Binary trees are tree based data structures where every node has at most two children (left and right). -In this exercise, every node stores an integer element. -From this we can build a binary search tree by requiring for every node that - - * values of elements in the left subtree are strictly smaller than the node's element - * values of elements in the right subtree are strictly bigger than the node's element - -In addition, there should be no duplicates, hence we obtain a binary tree set. - -Your task in this assignment is to implement an actor-based binary tree set where each node is -represented by one actor. The advantage of such an actor-based solution is that it can execute -fully asynchronously and in parallel. - -## The API - -You can find the message-based API for the actor-based binary tree to be implemented in the supplied `BinaryTreeSet` object -in the file `BinaryTreeSet.scala`. - -The operations, represented by actor messages, that the implementation should support are the following: - - * `Insert` - * `Remove` - * `Contains` - -All three of the operations expect an `ActorRef` representing the requester of the operation, a numerical identifier of -the operation and the element itself. `Insert` and `Remove` operations should result in an `OperationFinished` message sent -to the provided requester `ActorRef` reference including the id of the operation. `Insert` and `Remove` should return an -`OperationFinished` message even if the element was already present in the tree or was not found, respectively. -`Contains` should result in a `ContainsResult` message containing the result of the lookup (a Boolean which is -true if and only if the element is in the tree when the query arrives) and the identifier of the `Contains` query. - -## Handling of Removal - -You should observe that both the `Insert` and `Contains` operations share an important property, namely, they only -traverse a linear path from the root of the tree to the appropriate inner node or leaf. Since the tree nodes are actors -which process messages one-by-one, no additional synchronization is needed between these operations. Removal in a -binary tree unfortunately results in tree restructuring, which means that nodes would need to communicate and coordinate -between each other (while additional operations arrive from the external world!). - -Therefore, instead of implementing the usual binary tree removal, in your solution you should use a flag that is stored -in every tree node (`removed`) indicating whether the element in the node has been removed or not. This will result in a very -simple implementation that is concurrent and correct with minimal effort. Unfortunately this decision results in the -side effect that the tree set accumulates "garbage" (elements that have been removed) over time. - -## Garbage Collection - -As we have seen, removal of entries can be implemented simply by using a removal flag with the -added cost of growing garbage over time. To overcome this limitation you will need to implement a "garbage collection" -feature. Whenever your binary tree set receives a `GC` message, it should clean up all the removed elements, while -additional operations might arrive from the external world. - -The garbage collection task can be implemented in two steps. The first subtask is to implement an internal -`CopyTo` operation on the binary tree that copies all its non-removed contents from the binary tree to a provided new one. This -implementation can assume that no operations arrive while the copying happens (i.e. the tree is protected from modifications -while copying takes places). - -The second part of the implementation is to implement garbage collection in the manager (`BinaryTreeSet`) by using the copy operation. -The newly constructed tree should replace the old one and all actors from the old one should be stopped. -Since copying assumes no other concurrent operations, the manager should handle the case when operations arrive while still -performing the copy in the background. It is your responsibility to implement the manager in such a way that the fact -that garbage collection happens is invisible from the outside (of course additional delay is allowed). -For the sake of simplicity, your implementation should ignore GC requests that arrive while garbage collection is taking place. - -## Ordering Guarantees - -Replies to operations may be sent in any order but the contents of `ContainsResult` replies must obey the order of the -operations. To illustrate what this means observe the following example: - -Client sends: - - Insert(testActor, id=100, elem=1) - Contains(testActor, id=50, elem=2) - Remove(testActor, id=10, elem=1) - Insert(testActor, id=20, elem=2) - Contains(testActor, id=80, elem=1) - Contains(testActor, id=70, elem=2) - -Client receives: - - ContainsResult(id=70, true) - OperationFinished(id=20) - OperationFinished(id=100) - ContainsResult(id=80, false) - OperationFinished(id=10) - ContainsResult(id=50, false) - -While the results seem "garbled", they actually strictly correspond to the order of the original operations. On -closer examination you can observe that the order of original operations was [100, 50, 10, 20, 80, 70]. Now if you -order the responses according to this sequence the result would be: - - Insert(testActor, id=100, elem=1) -> OperationFinished(id=100) - Contains(testActor, id=50, elem=2) -> ContainsResult(id=50, false) - Remove(testActor, id=10, elem=1) -> OperationFinished(id=10) - Insert(testActor, id=20, elem=2) -> OperationFinished(id=20) - Contains(testActor, id=80, elem=1) -> ContainsResult(id=80, false) - Contains(testActor, id=70, elem=2) -> ContainsResult(id=70, true) - -As you can see, the responses the client received are the same, hence they must have been executed sequentially, -and only the responses have arrived out of order. Thus, the responses obey the semantics of sequential operations - -- it is simply their arrival order is not -defined. You might find it easier for testing to use sequential identifiers for the operations, since that makes it -easier to follow the sequence of responses. - -You might also note that out-of-order responses can only happen if the client does not wait for each individual answer -before continuing with sending operations. - -While this loose ordering guarantee on responses might look strange at first, it will significantly simplify the -implementation of the binary tree and you are encouraged to make full use of it. - -## Your task - -You can find code stubs in the file `BinaryTreeSet.scala` which provides you with the API as described above, -the `BinaryTreeSet` and `BinaryTreeNode` classes. The `BinaryTreeSet` represents the whole binary tree. -This is also the only actor that is explicitly created by the user and the only actor the user sends messages to. - -You can implement as many or as few message handlers as you like and you can add additional variables or helper -functions. We provide suggestions in your code stub, marked with the comment `optional`, but you are free to use -it fully or partially; the optional elements are not part of the tested API. - -To see a binary tree in operation check our provided tests in `BinaryTreeSuite.scala`. Note in particular -that it is the user who triggers garbage collection by sending a `GC` message (for the sake of simplicity of this exercise). - -Don't forget to make sure that no `Operation` messages interfere during garbage collection and that the user does -not receive any messages that may result from the copying process. To achieve this, put any incoming operation message -into a queue during the garbage collection process. When the copying process is finished, re-send the queued messages -to the tree root and clear the queue. - -The following may be useful for your implementation: - - * Another way to stop an actor, besides the `stop` method you have seen, is to send it a `PoisonPill` message. - * `context.parent` returns the ActorRef of the actor which created the current actor (i.e. its parent). - * If you see a log message like the following - - [INFO] [11/22/2013 14:04:13.237] [PostponeSpec-akka.actor.default-dispatcher-2] [akka://PostponeSpec/deadLetters] Message [actorbintree.BinaryTreeSet$OperationFinished] from Actor[akka://PostponeSpec/user/$e/my-actor#-1012560631] to Actor[akka://PostponeSpec/deadLetters] was not delivered. [1] dead letters encountered. - - it means that one of your messages (here the OperationFinished) message was not delivered from actor `my-actor` to actor `deadLetters`—the latter is where actors forward their messages after they terminate. - You should check that you do not stop actors prematurely. - -*A word on Actor counts:* - - * The grader verifies that enough Actors are created when inserting elements. - * The grader also verifies that enough Actors are stopped in response to a `GC` command (i.e. for those elements that were previously marked removed from the set). diff --git a/labs/lab9-kvstore/Readme.md b/labs/lab9-kvstore/Readme.md deleted file mode 100644 index d6041533f65736d07868fb3ed1fd2797b8f0e243..0000000000000000000000000000000000000000 --- a/labs/lab9-kvstore/Readme.md +++ /dev/null @@ -1,299 +0,0 @@ -# Key-Value Store - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b kvstore git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git cs206-kvstore -``` - -## Simple Replicated Key-Value store - -A key-value store is a very simple form of a database. Its entries are key-value pairs, the key part acting as a unique identifier, and the value being arbitrary data. In recent years, distributed versions of key-value stores have become very popular. -Your task in this assignment is to implement a distributed, replicated storage of key-value pairs. Each node (the replicas) in this distributed system will be represented by one actor. You will also have to define some helper actors. - -In the simplified version that we will examine, your system will include a primary node (the primary replica), -which will be responsible for replicating all changes to a set of secondary nodes (the secondary replicas). The primary and the secondary replica nodes will form a distributed database, where potential replica nodes might join and leave at arbitrary times. - -The primary replica will be the only one accepting modification events (insertions and removals) and replicate its current state to the secondaries. Both the primary and the secondary replicas will accept lookup (read) events, although the secondary nodes will be allowed to give results that are "out-of-date" since it takes time for the replicas to keep up with the changes on the primary replica. - -Compared to a full real-world solution several restricting assumptions are made about the system to make the problem easier to solve: - - * Updates are only possible on a dedicated node, the primary replica. - * The primary (leader) node does not fail during the uptime of the system. - * Membership is handled reliably by a provided subsystem (see section "The Arbiter"). - * The update rate is low, meaning that no incoming requests need to be rejected due to system overload. - * In case of rejecting an update the store is left in a possibly inconsistent state which may require a subsequent succeeding write to the same key to repair it. - * Clients are expected to not reuse request IDs before the request has been fully processed and responded to. - -For a more detailed discussion of these restrictions and on how lifting them would affect the solution please refer to the last section below. - -**This is a complex assignment. Please read the whole description before attempting to solve the exercise.** In the last section you will find a step-by-step list of which subtasks you need to solve in order to have a complete solution. If you are unable to arrive at a full solution due to time constraints, don’t despair, for you will have learnt a lot along the way. - -### Overview of the system components - -The key-value store and its environment consists of the following components: - - * **The clustered key-value store:** A set of nodes that store key value pairs in a distributed fashion, cooperating to maintain a certain set of guarantees (specified in section *“System Behavior - Consistency guarantees”*). This cluster of nodes consists of replicas and the provided `Arbiter` and `Persistence` modules: - * **Primary replica** A distinguished node in the cluster that accepts updates to keys and propagates the changes to secondary replicas. - * **Secondary replicas** Nodes that are in contact with the primary replica, accepting updates from it and serving clients for read-only operations. - * **Arbiter:** A subsystem that is provided in this exercise and which assigns the primary or secondary roles to your nodes. - * **Persistence:** A subsystem that is provided in this exercise and which offers to persist updates to stable storage, but might fail spuriously. - * **Clients:** Entities that communicate with one of the replicas to update or read key-value pairs. - -You are encouraged to use additional actors in your solution as you see fit. - -### Clients and The KV Protocol - -Clients are external entities contacting the replica set (your cluster) for reading and writing key-value pairs. It is your responsibility to maintain the consistency guarantees for clients that are described in the next section. -Each node participating in the key-value store (primary and secondaries) provides an interface for clients. This interface is a set of messages and corresponding answers that together form the KV Protocol. - -The KV Protocol itself contains two subsets of operations: - - 1. Update operations (insertion and removal). - 2. Lookup operation. - -Clients contacting the primary node directly can use all operations on the key-value store, while clients contacting the secondaries can only use lookups. - -The two sets of operations in detail are: - -__Update Commands__ - - * `Insert(key, value, id)` - This message instructs the primary to insert the (key, value) pair into the storage and replicate it to the secondaries: `id` is a client-chosen unique identifier for this request. - * `Remove(key, id)` - This message instructs the primary to remove the key (and its corresponding value) from the storage and then remove it from the secondaries. - * A successful `Insert` or `Remove` results in a reply to the client (precisely: to the `sender` of the update command) in the form of an `OperationAck(id)` message where the `id` field matches the corresponding id field of the operation that has been acknowledged. - * A failed `Insert` or `Remove` command results in an `OperationFailed(id)` reply. A failure is defined as the inability to confirm the operation within 1 second. See the sections on replication and persistence below for more details. - -__Lookup__ - - * `Get(key, id)` - Instructs the replica to look up the "current" (what current means is described in detail in the next section) value assigned with the key in the storage and reply with the stored value. - * A `Get` operation results in a `GetResult(key, valueOption, id)` message to be sent back to the `sender` of the lookup request where the `id` field matches the value in the `id` field of the corresponding `Get` message. The `valueOption` field should contain `None` if the key is not present in the replica or `Some(value)` if a value is currently assigned to the given key in that replica. - -**All replies sent by the Replica shall have that Replica as their `sender`.** - -### System Behavior - Consistency guarantees - -Let's assume the scenario that one client issues the following commands to the primary replica (starting from empty storage), **waiting for successful acknowledgement of each operation before proceeding with the next** (see further below for the case of not awaiting confirmation): - - Insert("key1", "a") - Insert("key2", "1") - Insert("key1", "b") - Insert("key2", "2") - -#### Ordering guarantees for clients contacting the primary replica - -A second client reading directly from the primary is not allowed to see: - - * `key1` containing `b` and then containing `a` *(since `a` was written before `b` for `key1`)* - * `key2` containing `2` and then containing `1` *(since `1` was written before `2` for `key2`)* - -In other words, this second client sees the updates in order (although it might miss some updates, so it might see the value `2` for `key2` immediately without seeing the intermediate value `1`). - -In contrast, the second client may observe - - * `key1` containing `b` and then `key2` containing `1` - * `key2` containing `2` and then `key1` containing `a` - - -This means that the ordering guarantee only applies between reads and write *to the same key*, not across keys. The store may choose to provide stronger semantics to respect ordering across different keys, but clients will not be able to rely on this; the reason is that lifting the restriction of having only one non-failing primary replica would require breaking these stronger guarantees. - -#### Ordering guarantees for clients contacting a secondary replica - -For a second client reading from one of the secondary replicas (during a conversation, the replica does not change) the exact same requirements apply as if that client was reading from the primary, with the following addition: - - * it must be guaranteed that a client reading from a secondary replica will eventually see the following (at some point in the future): - - * `key1` containing `b` - * `key2` containing `2` - -#### Ordering guarantees for clients contacting different replicas - -If a second client asks different replicas for the same key, it may observe different values during the time window when an update is disseminated. The client asking for `key1` might see - - * answer `b` from one replica - * and subsequently answer `a` from a different replica - -As per the rule stated in the previous section, and assuming that the client keeps asking repeatedly, eventually all reads will result in the value `b` if no other updates are done on `key1`. - -*Eventual consistency* means that given enough time, all replicas settle on the same view. This also means that when you design your system **clients contacting multiple replicas at the same time are not required to see any particular ordering.** You do not need to design your solution for such scenarios and the grading system will not test these either. - -#### Durability guarantees of updates for clients contacting the primary replica - -The previous two sections prescribed possible transitions that the clients are allowed to experience on key updates. In this section, we will see what guarantees acknowledgement messages must obey (on the primary replica). - -Whenever the primary replica receives an update operation (either `Insert` or `Remove`) it **must** reply with an `OperationAck(id)` or `OperationFailed(id)` message, to be sent at most 1 second after the update command was processed (the ActorSystem’s timer resolution is deemed to be sufficiently precise for this). - -A positive `OperationAck` reply must be sent as soon as - - * the change in question has been handed down to the `Persistence` module (provided) **and** a corresponding acknowledgement has been received from it *(the persistence module is "flaky"—it fails randomly from time to time—and it is your task to keep it alive while retrying unacknowledged persistence operations until they succeed, see the persistence section for details)* - * replication of the change in question has been initiated **and** all of the secondary replicas have acknowledged the replication of the update. - - If replicas leave the cluster, which is signalled by sending a new `Replicas` message to the primary, then outstanding acknowledgements of these replicas must be waived. This can lead to the generation of an `OperationAck` triggered indirectly by the `Replicas` message. - -A negative `OperationFailed` reply must be sent if the conditions for sending an `OperationAck` are not met within the 1 second maximum response time. - -#### Consistency in the case of failed replication or persistence - -Assuming in the above scenario that the last write fails (i.e. an `OperationFailed` is returned), replication to some replicas may have been successful while it failed on others. Therefore in this case the property that eventually all replicas converge on the same value for `key2` is not provided by this simplified key–value store. In order to restore consistency a later write to `key2` would have to succeed. Lifting this restriction is an interesting exercise on its own, but it is outside of the scope of this course. - -One consequence of this restriction is that each replica uses this freedom to immediately hand out the updated value to subsequently reading clients, even before the the new value has been persisted locally, and no rollback is attempted in case of failure. - -#### Which value to expect while an update is outstanding? - -Sending an update request for a key followed by a `Get` request for the same key without waiting for the acknowledgement of the update is allowed to return either the old or the new value (or a third value if another client concurrently updates the same key). An example, assuming only this one client at this time: - - Insert("key1", "a") - <await confirmation> - Insert("key1", "b") - Get("key1") - -The replies for the last two requests may arrive in any order, and the reply for the `Get` request may either contain `"a"` or `"b"`. - -### The Arbiter - -The `Arbiter` is an external subsystem that will be provided for use. The Arbiter follows a simple protocol: - - * New replicas must first send a `Join` message to the `Arbiter` signaling that they are ready to be used. - * The `Join` message will be answered by either a `JoinedPrimary` or `JoinedSecondary` message indicating the role of the new node; the answer will be sent to the `sender` of the `Join` message. The first node to join will get the primary role, other subsequent nodes are assigned the secondary role. - * The arbiter will send a `Replicas` message to the primary replica whenever it receives the `Join` message; for this reason the `sender` of the `Join` message must be the replica Actor itself. This message contains the set of available replica nodes including the primary and all the secondaries. - * All messages sent by the Arbiter will have the Arbiter as their `sender`. - -### The Replicas - -You have to provide an Actor representing a node of the system. Its declaration is: - - class Replica(val arbiter: ActorRef) extends Actor - -Please note that in this exercise the nodes (i.e. actors) are executed within the same JVM, but the problems and their solutions apply equally when distributing the system across multiple network hosts. - -When your actor starts, it must send a `Join` message to the Arbiter and then choose between primary or secondary behavior according to the reply of the `Arbiter` to the `Join` message (a `JoinedPrimary` or `JoinedSecondary` message). - -The primary replica must provide the following features: - - * The primary must accept update and lookup operations from clients following the Key-Value protocol like `Insert`, `Remove` or `Get` as it is described in the *“Clients and The KV Protocol”* section, respecting the consistency guarantees described in *“Guarantees for clients contacting the primary replica”*. - * The primary must replicate changes to the secondary replicas of the system. It must also react to changes in membership (whenever it gets a `Replicas` message from the `Arbiter`) and start replicating to newly joined nodes, and stop replication to nodes that have left; the latter implies terminating the corresponding `Replicator` actor. More details can be found in the section *“Replication Protocol”*. - -The secondary replicas must provide the following features: - - * The secondary nodes must accept the lookup operation (`Get`) from clients following the Key-Value protocol while respecting the guarantees described in *“Guarantees for clients contacting the secondary replica”*. - * The replica nodes must accept replication events, updating their current state (see *“Replication Protocol”*). - -### The Replication Protocol - -Apart from providing the KV protocol for external clients, you must implement another protocol involving the primary and secondary replicas and some newly introduced helper nodes. The KV store will use this protocol to synchronize its state between nodes. - -When a new replica joins the system, the primary receives a new `Replicas` message and must allocate a new actor of type `Replicator` for the new replica; when a replica leaves the system its corresponding `Replicator` must be terminated. The role of this `Replicator` actor is to accept **update events**, and propagate the changes to its corresponding replica (i.e. there is exactly one `Replicator` per secondary replica). **Also, notice that at creation time of the `Replicator`, the primary must forward update events for every key-value pair it currently holds to this `Replicator`.** - -Your task for this protocol will be to provide an Actor representing a `Replicator`. Its declaration is: - - class Replicator(val replica: ActorRef) extends Actor - -The protocol includes two pairs of messages. The first one is used by the replica actor which requests replication of an update: - - * `Replicate(key, valueOption, id)` is sent to the `Replicator` to initiate the replication of the given update to the `key`; in case of an `Insert` operation the `valueOption` will be `Some(value)` while in case of a `Remove` operation it will be `None`. The `sender` of the `Replicate` message shall be the Replica itself. - - * `Replicated(key, id)` is sent as a reply to the corresponding `Replicate` message once replication of that update has been successfully completed (see `SnapshotAck`). The `sender` of the `Replicated` message shall be the Replicator. - -The second pair is used by the replicator when communicating with its partner replica: - - * `Snapshot(key, valueOption, seq)` is sent by the `Replicator` to the appropriate secondary replica to indicate a new state of the given key. `valueOption` has the same meaning as for `Replicate` messages. The `sender` of the `Snapshot` message shall be the Replicator. - - The `Snapshot` message provides a sequence number (`seq`) to enforce ordering between the updates. Updates for a given secondary replica must be processed in contiguous ascending sequence number order; this ensures that updates for every single key are applied in the correct order. Each `Replicator` uses its own number sequence starting at zero. - - When a snapshot arrives at a `Replica` with a sequence number which is greater than the currently expected number, then that snapshot must be ignored (meaning no state change and no reaction). - - When a snapshot arrives at a `Replica` with a sequence number which is smaller than the currently expected number, then that snapshot must be ignored and immediately acknowledged as described below. - - The sender reference when sending the `Snapshot` message must be the `Replicator` actor (not the primary replica actor or any other). - - * `SnapshotAck(key, seq)` is the reply sent by the secondary replica to the `Replicator` as soon as the update is persisted locally by the secondary replica. The replica might never send this reply in case it is unable to persist the update. The `sender` of the `SnapshotAck` message shall be the secondary Replica. - - The acknowledgement is sent immediately for requests whose sequence number is less than the next expected number. - - The expected number is set to the greater of - * the previously expected number - * the sequence number just acknowledged, incremented by one - -You should note that the Replicator may handle multiple snapshots of a given key in parallel (i.e. their replication has been initiated but not yet completed). It is allowed—but not required— to batch changes before sending them to the secondary replica, provided that each replication request is acknowledged properly and in the right sequence when complete. An example: - - Replicate("a_key", Some("value1"), id1) - Replicate("a_key", Some("value2"), id2) - -might have reached the `Replicator` before it got around to send a `Snapshot` message for `a_key` to its replica. These two messages could then result in only the following replication message - - Snapshot("a_key", Some("value2"), seq) - -skipping the state where `a_key` contains the value `value1`. - -Since the replication protocol is meant to symbolize remote replication you must consider the case that either a `Snapshot` message or its corresponding `SnapshotAck` message is lost on the way. Therefore the `Replicator` must make sure to periodically retransmit all unacknowledged changes. For grading purposes it is assumed that this happens roughly every 100 milliseconds. To allow for batching (see above) we will assume that a lost `Snapshot` message will lead to a resend at most 200 milliseconds after the `Replicate` request was received (again, the ActorSystem’s scheduler service is considered precise enough for this purpose). - -### Persistence - -Each replica will have to submit incoming updates to the local `Persistence` actor and wait for its acknowledgement before confirming the update to the requester. In case of the primary, the requester is a client which sent an `Insert` or `Remove` request and the confirmation is an `OperationAck`, whereas in the case of a secondary the requester is a `Replicator` sending a `Snapshot` and expecting a `SnapshotAck` back. - -The used message types are: - - * `Persist(key, valueOption, id)` is sent to the `Persistence` actor to request the given state to be persisted (with the same field description as for the `Replicate` message above). - * `Persisted(key, id)` is sent by the `Persistence` actor as reply in case the corresponding request was successful; no reply is sent otherwise. The reply is sent to the `sender` of the `Persist` message. Note, however, that the `sender` of the `Persisted` message might not be the `Persistence` actor (in some tests, the `Persisted` message will be sent by a wrapper actor). - -The provided implementation of this persistence service is a mock in the true sense, since it is rather unreliable: every now and then it will fail with an exception and not acknowledge the current request. It is the job of the `Replica` actor to create and appropriately supervise the `Persistence` actor; for the purpose of this exercise any strategy will work, which means that you can experiment with different designs based on resuming, restarting or stopping and recreating the `Persistence` actor. To this end your `Replica` does not receive an `ActorRef` but a `Props` for this actor, implying that the `Replica` has to initially create it as well. - -For grading purposes it is expected that `Persist` is retried before the 1 second response timeout in case persistence failed. The `id` used in retried `Persist` messages must match the one which was used in the first request for this particular update. - -### Your Task - -Since this assignment is a longer one, we have prepared the test suite in a way that supports the solution step by step. In the following you can find a suggestion for how to proceed with the solution, but you can of course choose any path leading up to twenty points that you like. - -1. Implement the primary replica role so that it correctly responds to the KV protocol messages without considering persistence or replication. -2. Implement the secondary replica role so that it correctly responds to the read-only part of the KV protocol and accepts the replication protocol, without considering persistence. -3. Implement the replicator so that it correctly mediates between replication requests, snapshots and acknowledgements. -4. Implement the use of persistence at the secondary replicas. -5. Implement the use of persistence and replication at the primary replica. -6. Implement the sending of the initial state replication to newly joined replicas. - -### Hints, Tips - -The logic for collecting acknowledgements of persistence and replication can be made such that it is usable both in primary and secondary replicas. - -You should write (versions of) tests which exercise the behavior under unreliable persistence (i.e. when using a `Persistence` actor created with `flaky = true`) or unreliable communication between primary and secondaries. The latter can be done by having the `Arbiter` wrap the secondary nodes’ ActorRefs in small actors which normally forward messages but sometimes forget to do so. The grading process involves such a test suite as well. - -Resending snapshots from the `Replicator` without pause is not the intended solution—the resend rate needs to be kept reasonable. This fact is exploited implicitly by the test suite in step 3. - -### The Effect of the Restrictions - -This section is meant to offer further insights for those who want to take the assignment as a starting point for continuing their own studies beyond what the course provides. It is not necessary to read this section in order to complete the assignment. - -#### Updates are only accepted by a distinguished primary replica - -Accepting writes only on one node at any given time simplifies conflict resolution, because request arrival order at that node can be used to serialize updates to a given key. The downside of this is that this node clearly limits the amount of requests that can be handled per second, it is a single point of bottleneck. - -In order to scale the possible update rate beyond what a single node can digest it would also be possible to divide the key space into shards and distribute them across the members, making each member a primary for a certain portion of the key space. The clients would then need to either be told which one the right node is for updating a certain key, or every node could include a ConsistentHashingRouter which dispatches incoming requests to the right node on the client’s behalf (see the diagram below). Moving the primary role for a shard from one member to another would then be necessary to rebalance the allocation when nodes join or leave the cluster. - - - -The service which determines the placement of shards does not need to be a single point of bottleneck, as we can see the distribution of shards by using consistent hashing can be done without going through a central point. The only thing that needs special care is the hand-off period when shards move between nodes. - -#### The primary node does not fail - -A real system would have to tolerate a failure of the primary node, which otherwise would be a single point of failure, making the system not resilient. In order to support this, the primary role must be transferred by the arbiter to another node, which transitions from secondary to primary and starts accepting updates. During this transition updates will be left without a reply, but since confirmations are only sent out after all replicas have acknowledged an update, the new primary node will be able to continue where the old one left off. - -One problem are unconfirmed or even rejected updates which have in fact been accepted by all secondary replicas. The store will in this case be internally consistent, but its contents possibly does not match what the client assumes if it received an `OperationFailed` message. Having received that message signals a possibly inconsistent state due to other reasons as well, and it could be an option to require the client to attempt to repair it by sending another write to the same key if needed. - -#### Membership is handled reliably by a provided subsystem - -A service which reliably handles membership is available in the form of the Akka Cluster module. The arbiter of this assignment can be a [ClusterSingleton](http://doc.akka.io/docs/akka/2.2.3/scala/cluster-usage.html#Cluster_Singleton_Pattern) to which replicas register and which uses DeathWatch to monitor them, or the cluster membership list could be used directly, determining the primary role by sorting the member addresses and using the first one. - -#### The update rate is low - -Without this restriction the resend mechanism for example in the `Replicator` would have to manage the size of the buffer in which snapshots are kept while awaiting their acknowledgement. This means that the replication mechanism could either lose updates or the `Replica` would need to start rejecting requests with `OperationFailed` as soon as a limit on the number of outstanding requests is exceeded. - -Especially when considering the next restriction, latency of confirmations is a performance sensitive topic. One further possible optimization is to distribute the burden of ensuring consistency between the primary and secondary nodes by requiring that only a certain number of secondaries have sent their confirmation before acknowledging an update. In order to restore consistency in case of a replication failure (e.g. if the primary stops working for whatever reason) the secondaries have to ask their peers for the key and a reply is only sent once enough have replied with the same value. If the number of write confirmations is W and the count of agreeing reads is denoted R, then the condition for consistency is R+W>N, where N is the total number of replicas. This equation must be interpreted with some care because N can change during a replication or read process. - -#### Disregarding inconsistencies after OperationFailed - -This is the toughest restriction to lift because it touches on the fundamental choice of which flavor of weak consistency eventually shall be reached. The restriction allows the system to stay responsive in case of failure (by providing an `OperationFailed` reply), but making that reply mean that the update will eventually disappear from all nodes is not possible in general. - -Assuming that the primary does not fail for a sufficiently long time period after the operation failure, the first step would be to ensure that for a given key only up to one update can be “in flight” at any given time. If the primary determines that this update has failed, it will then replicate the previous state for that key to all replicas, awaiting confirmation without a timeout. This favors consistency over availability, since it makes the service of updating that key unavailable while the system is experiencing a malfunction. - -#### Clients are expected not to reuse request IDs - -This restriction makes your solution simpler and it also removes the need for some grading tests which would have been hard to formulate in a way which does not assume too much about your solution. In a real system you might even find this restriction as specified operational requirement. diff --git a/labs/tools-setup.md b/labs/tools-setup.md deleted file mode 100644 index 88a602db5385ec8f6f72d4c348fd58b1b71fbbbc..0000000000000000000000000000000000000000 --- a/labs/tools-setup.md +++ /dev/null @@ -1,127 +0,0 @@ -# Tools Setup - -## Note - -We recommend using Linux or macOS for this course, we also support Windows but -typically people have more trouble getting everything working correctly on -Windows and it's harder for us to help them since we don't use Windows -ourselves. - -**On Windows, if your username has spaces or special characters in it, the IDE might not -work properly. Please create a new user with a username containing only letters.** - -## Step 1: Create an account on gitlab.epfl.ch - -If you haven't already [log into gitlab](https://gitlab.epfl.ch/users/sign_in) -and fill in [this form](https://forms.gle/N6F3Q3jZm71AASby9) with your GASPAR and SCIPER number to initialize your GitLab repository for the course. Do this as soon as possible because it will take some time between the account creation and the lab submission system working for your account. - -## Step 2: Installing the Java Development Kit (JDK) and sbt via coursier - -We will use coursier to install the correct version of -Java as well as the sbt build tool. Follow [the instructions on the coursier website](https://get-coursier.io/docs/cli-installation) for the installation. - -_Note_: on Windows, you might have to run the installer twice. - -## Step 3: Installing git - -git is a version control system. - -### On Ubuntu and Debian - -```shell -sudo apt update && sudo apt install git -``` - -### On macOS - -First, install the Homebrew package manager if it is not already installed: - -```shell -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -``` - -Use Homebrew to install git: - -```shell -brew install git -``` - -### On Windows - -Download and install git from [https://git-scm.com/downloads](https://git-scm.com/downloads). -Once git is installed, open a **new** terminal and run: - -```shell -git config --global core.autocrlf false -``` - -If this command worked it will not print anything. - -## Step 4: Installing Code - -Visual Studio Code is the IDE we strongly recommend using for this class (you are free to use any editor you want, but we won't don't have the resources to help you configure it for Scala). - -### On Linux - -See [https://code.visualstudio.com/docs/setup/linux](https://code.visualstudio.com/docs/setup/linux) - -### On macOS - -If you don't already have Code installed: -```shell -brew install --cask visual-studio-code -``` -If it was already installed before, you will need to [enable launching it from the -command line](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line). - -### On Windows - -See [https://code.visualstudio.com/docs/setup/windows](https://code.visualstudio.com/docs/setup/windows). -Make sure that the checkbox "Add to PATH (available after restart)" in the -installer is checked. - -## Step 5: Installing the Scala support for Code - -Open a **new** terminal and run: -```scala -code --install-extension lampepfl.dotty-syntax -``` - -If you're on Windows and the command is not found, try closing and restarting -the terminal, if that doesn't work - -## Step 6: Generate a public/private SSH key pair - -To submit labs, you will need an SSH key. If you don't already have one, here's how to generate it: - -### Step 6.1: Installing OpenSSH - -#### On Ubuntu and Debian - -```shell -sudo apt update && sudo apt install openssh-client -``` - -#### On macOS - -Nothing to do, OpenSSH is pre-installed - -#### On Windows - -Follow the instructions under "Enable OpenSSH Client in Windows 10" on -[https://winaero.com/blog/enable-openssh-client-windows-10/](https://winaero.com/blog/enable-openssh-client-windows-10/) - -### Step 6.2: Generating the key pair - -Please follow [this tutorial](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) to generate a new SSH key and add it to the ssh-agent (except the last step: you should instead add the key to Gitlab as described below). This [video](https://youtu.be/_RsP81Et12s?t=67) (from 1:07 to 4:05) might also help. - -### Step 6.3: Adding your public key on Gitlab - -To be able to push your code, you'll need to add the public part of your key on Gitlab: -- Go to [gitlab.epfl.ch](https://gitlab.epfl.ch), log in with your EPFL account -- Go to [gitlab.epfl.ch/-/profile/keys](https://gitlab.epfl.ch/-/profile/keys) and copy-paste the content of the `id_rsa.pub` file created by the `ssh-keygen` command you just ran (`ssh-keygen` prints the location of the file to the console). -- Press `Add key` - -## Step 7: Follow the example lab - -Time to do the [example lab](example-lab.md)! diff --git a/midterm/CM_1_3_numbered.pdf b/midterm/CM_1_3_numbered.pdf deleted file mode 100644 index bb3c7d3bcc2eab8c8e9162ed061bc09a8398f995..0000000000000000000000000000000000000000 Binary files a/midterm/CM_1_3_numbered.pdf and /dev/null differ diff --git a/midterm/CO_1_numbered.pdf b/midterm/CO_1_numbered.pdf deleted file mode 100644 index 73dc08a23d73adb08b07ded89c4fec923e713fa8..0000000000000000000000000000000000000000 Binary files a/midterm/CO_1_numbered.pdf and /dev/null differ diff --git a/midterm/INM_200_numbered.pdf b/midterm/INM_200_numbered.pdf deleted file mode 100644 index 2de8fbe05d6cdfd3720ba1627b5cff2cfacd26f8..0000000000000000000000000000000000000000 Binary files a/midterm/INM_200_numbered.pdf and /dev/null differ diff --git a/midterm/Mock Exam.pdf b/midterm/Mock Exam.pdf deleted file mode 100644 index a1a7224355680d0ddba94a88c76d4268cdc182fc..0000000000000000000000000000000000000000 Binary files a/midterm/Mock Exam.pdf and /dev/null differ diff --git a/midterm/Students and Seats.pdf b/midterm/Students and Seats.pdf deleted file mode 100644 index 6cd6cb99b1e1035f6d947d8b1392ea4efdedf22c..0000000000000000000000000000000000000000 Binary files a/midterm/Students and Seats.pdf and /dev/null differ diff --git a/previous-exams/2015-midterm-solution-.pdf b/previous-exams/2015-midterm-solution-.pdf deleted file mode 100644 index 9d3c70f6de625b9e3b5a5eca6b97947b2805dc41..0000000000000000000000000000000000000000 Binary files a/previous-exams/2015-midterm-solution-.pdf and /dev/null differ diff --git a/previous-exams/2015-midterm.pdf b/previous-exams/2015-midterm.pdf deleted file mode 100644 index 23f21555aa3bf7a7669cc79de54acda90aa19099..0000000000000000000000000000000000000000 Binary files a/previous-exams/2015-midterm.pdf and /dev/null differ diff --git a/previous-exams/2016-final-solutions.pdf b/previous-exams/2016-final-solutions.pdf deleted file mode 100644 index 8e60022aef7b0d25179ca1b4dca4f1338c16619d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-final-solutions.pdf and /dev/null differ diff --git a/previous-exams/2016-final.pdf b/previous-exams/2016-final.pdf deleted file mode 100644 index c13bc385e9713d3b01485ec0a22bb58ddaece0d5..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-final.pdf and /dev/null differ diff --git a/previous-exams/2016-midterm-solutions.pdf b/previous-exams/2016-midterm-solutions.pdf deleted file mode 100644 index 22237321a68102b97970ebe1f9f9a51b2a25792c..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-midterm-solutions.pdf and /dev/null differ diff --git a/previous-exams/2016-midterm.pdf b/previous-exams/2016-midterm.pdf deleted file mode 100644 index 0b83f5a93befc1b6e5bdc2bc42e805de5f9052bc..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-midterm.pdf and /dev/null differ diff --git a/previous-exams/2017-final-solutions.pdf b/previous-exams/2017-final-solutions.pdf deleted file mode 100644 index 336c0869de172b028299532162c5239085fa1f08..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-final-solutions.pdf and /dev/null differ diff --git a/previous-exams/2017-final.pdf b/previous-exams/2017-final.pdf deleted file mode 100644 index 477dd837c75874d8c02897571d192bbaf9678479..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-final.pdf and /dev/null differ diff --git a/previous-exams/2017-midterm-solutions.pdf b/previous-exams/2017-midterm-solutions.pdf deleted file mode 100644 index b02c50f258d5bca20b19882e239db4b7608d486e..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-midterm-solutions.pdf and /dev/null differ diff --git a/previous-exams/2017-midterm.pdf b/previous-exams/2017-midterm.pdf deleted file mode 100644 index aa1cbf26b9840f9c89513545e83211f9116cb8b3..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-midterm.pdf and /dev/null differ diff --git a/previous-exams/2018-final-solutions.pdf b/previous-exams/2018-final-solutions.pdf deleted file mode 100644 index 5742cab8f4c696feb10ff93c67a3ac43831cec03..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-final-solutions.pdf and /dev/null differ diff --git a/previous-exams/2018-final.pdf b/previous-exams/2018-final.pdf deleted file mode 100644 index be1016c8c9e62dcf1233c52372d8729ebab4c3f7..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-final.pdf and /dev/null differ diff --git a/previous-exams/2019-final-solutions.pdf b/previous-exams/2019-final-solutions.pdf deleted file mode 100644 index 6029535ca8448952d37c40af628c06bd445254b9..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-final-solutions.pdf and /dev/null differ diff --git a/previous-exams/2019-final.pdf b/previous-exams/2019-final.pdf deleted file mode 100644 index c08c74faf5121f78e58254848321ff2bf729bb04..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-final.pdf and /dev/null differ diff --git a/previous-exams/2019-midterm-solutions.pdf b/previous-exams/2019-midterm-solutions.pdf deleted file mode 100644 index a311ee467b7fcd4dfbf6cdb0f367dcebc6bba366..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-midterm-solutions.pdf and /dev/null differ diff --git a/previous-exams/2019-midterm.pdf b/previous-exams/2019-midterm.pdf deleted file mode 100644 index d64aac32c34858734b9f7a8005986e38759ccfa1..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-midterm.pdf and /dev/null differ diff --git a/previous-exams/2020-final-solution.pdf b/previous-exams/2020-final-solution.pdf deleted file mode 100644 index 9872cc3273525b79c1cfd3d71cd70a6ec6541e45..0000000000000000000000000000000000000000 Binary files a/previous-exams/2020-final-solution.pdf and /dev/null differ diff --git a/previous-exams/2020-final.pdf b/previous-exams/2020-final.pdf deleted file mode 100644 index 2d70a411e7f0294dda265eb9d13ae2f0355dbde1..0000000000000000000000000000000000000000 Binary files a/previous-exams/2020-final.pdf and /dev/null differ diff --git a/previous-exams/2021-final-solutions/concpar21final01/.gitignore b/previous-exams/2021-final-solutions/concpar21final01/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final-solutions/concpar21final01/assignment.sbt b/previous-exams/2021-final-solutions/concpar21final01/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final-solutions/concpar21final01/build.sbt b/previous-exams/2021-final-solutions/concpar21final01/build.sbt deleted file mode 100644 index 8296da33001986056a2bf7795d99dff74bd23000..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/build.sbt +++ /dev/null @@ -1,19 +0,0 @@ -course := "concpar" -assignment := "concpar21final01" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -enablePlugins(PlayScala) -disablePlugins(PlayLayoutPlugin) - -libraryDependencies := libraryDependencies.value.map(dep => - if(dep.organization == "com.typesafe.play") dep.cross(CrossVersion.for3Use2_13) - else dep -) - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/CourseraStudent.scala b/previous-exams/2021-final-solutions/concpar21final01/project/CourseraStudent.scala deleted file mode 100644 index 0d5da7fa7f25c17bb2a559138862b471f38788bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/CourseraStudent.scala +++ /dev/null @@ -1,212 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scala.util.{Failure, Success, Try} -import scalaj.http._ -import play.api.libs.json.{Json, JsObject, JsPath} - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(courseId: String, key: String, partId: String, itemId: String, premiumItemId: Option[String]) - - -object CourseraStudent extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import StudentTasks.autoImport._ - import MOOCSettings.autoImport._ - import autoImport._ - - override lazy val projectSettings = Seq( - submitSetting, - ) - - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - StudentTasks.scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "progfun1" => "scala-functional-programming" - case "progfun2" => "scala-functional-program-design" - case "parprog1" => "scala-parallel-programming" - case "bigdata" => "scala-spark-big-data" - case "capstone" => "scala-capstone" - case "reactive" => "scala-akka-reactive" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - StudentTasks.failSubmit() - } - - val base64Jar = StudentTasks.prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } - -} diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/MOOCSettings.scala b/previous-exams/2021-final-solutions/concpar21final01/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/StudentTasks.scala b/previous-exams/2021-final-solutions/concpar21final01/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/build.properties b/previous-exams/2021-final-solutions/concpar21final01/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/buildSettings.sbt b/previous-exams/2021-final-solutions/concpar21final01/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final-solutions/concpar21final01/project/plugins.sbt b/previous-exams/2021-final-solutions/concpar21final01/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final-solutions/concpar21final01/src/main/resources/application.conf b/previous-exams/2021-final-solutions/concpar21final01/src/main/resources/application.conf deleted file mode 100644 index b2f71b4b890ae4198c93f926848ce4a13d4eb801..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/src/main/resources/application.conf +++ /dev/null @@ -1 +0,0 @@ -play.application.loader=concpar21final01.MyApplicationLoader diff --git a/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala b/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala deleted file mode 100644 index 5b960ec66c0344e9f0751d02523c5b1a47e5e519..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala +++ /dev/null @@ -1,92 +0,0 @@ -package concpar21final01 - -import play.api.{ApplicationLoader, BuiltInComponentsFromContext} -import play.api.mvc.Results.Ok -import play.api.routing.sird.* -import play.api.routing.Router -import play.api.ApplicationLoader.Context -import play.filters.HttpFiltersComponents - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future -import scala.util.Random - -class MyApplicationLoader extends ApplicationLoader: - def load(context: Context) = - new MyComponents(context).application - -class MyComponents(context: Context) - extends BuiltInComponentsFromContext(context) - with HttpFiltersComponents: - - lazy val router = Router.from { case GET(p"/") => - Action.async { - (new Problem1MockData) - .leaderboard() - .map(leaderboardHTML) - .map(Ok(_).as("text/html")) - } - } - - def leaderboardHTML(data: List[Grade]): String = - s""" - |<!DOCTYPE html> - |<html> - | <head> - | <title>Leaderboard</title> - | </head> - | <body> - | <h1>Leaderboard:</h1> - | <ul> - | ${data - .map { case Grade(sciper, g) => - val grade = "%1.2f".format(g) - s"<li>$sciper : $grade</li>" - } - .mkString("\n ")} - | </ul> - | </body> - |</html> - """.trim.stripMargin - -class Problem1MockData extends Problem1: - def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - // In an actual implementation, this is where we would make a call to - // the GitLab APIs. This mock returns a random grade after a short delay. - Thread.sleep(15) // GitLab is pretty fast today... - val rand = new Random(sciper) - val grade = rand.nextInt(6).toDouble + rand.nextDouble() - if sciper < 100000 || sciper > 999999 || sciper % 10 == 0 then None - else Some(Grade(sciper, grade)) - } - - /** Retrieve the list of enrolled students from IS-academia - */ - def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List( // A fake list of SCIPER numbers - 301425, 207372, 320658, 300217, 224523, 301068, 331020, 331095, 320270, - 320742, 299310, 300974, 322202, 343357, 302632, 343366, 320229, 269364, - 320004, 321830, 219188, 300834, 320992, 299237, 298016, 300397, 269857, - 300492, 300481, 279254, 320967, 300443, 300329, 300305, 331158, 310402, - 279067, 300682, 259825, 351616, 310869, 301215, 299481, 269375, 351249, - 310866, 351141, 301530, 361378, 351661, 351524, 311081, 331137, 332319, - 301045, 300393, 300308, 310889, 310064, 310841, 351333, 310382, 333887, - 333837, 320832, 321397, 351691, 269125, 312732, 351546, 301783, 351698, - 310775, 331388, 311139, 301992, 301578, 361760, 351174, 310298, 300666, - 259778, 301554, 301278, 301669, 321372, 311347, 321129, 351490, 321189, - 301336, 341560, 331220, 331129, 333927, 279186, 310596, 299135, 279226, - 310507, 269049, 300309, 341524, 351143, 300785, 310612, 320338, 259980, - 269952, 310397, 320246, 310959, 301454, 301835, 301802, 301649, 301170, - 301908, 351708, 321046, 361490, 311070, 351830, 311054, 311912, 301913, - 361232, 301030, 351723, 311472, 311166, 321057, 310793, 269462, 311948, - 321693, 321056, 361765, 301453, 321626, 341490, 320892, 269871, 269580, - 320199, 320908, 320830, 269071, 380542, 253768, 311204, 269127, 351073, - 341327, 301792, 299789, 361424, 301525, 311637, 321423, 279111, 330126, - 310371, 259888, 269525, 299585, 300147, 341402, 330067, 311796, 279037, - 248517, 301436, 269965, 259963, 320720, 248583, 259709, 361204, 341500, - 311803, 299981, 311832, 301088, 259649, 279183, 341760, 311844, 279079, - 390997, 311917, 390999, 361122, 301208, 311538, 272943, 361570, 390959) - } diff --git a/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/Problem1.scala b/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/Problem1.scala deleted file mode 100644 index fbb9ae49aaf18ee0dbb1b2b094b61b805032f7b7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/src/main/scala/concpar21final01/Problem1.scala +++ /dev/null @@ -1,29 +0,0 @@ -package concpar21final01 - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future - -case class Grade(sciper: Int, grade: Double) - -trait Problem1: - /** Retrieve the list of student grades, sorted such that maximum grades - * appear at the head of the list. - */ - def leaderboard(): Future[List[Grade]] = - - getScipers() - .flatMap { scipers => - Future.sequence(scipers.map(getGrade)) - } - .map(_.flatten.sortBy(_.grade).reverse) - - /** Retrieve a student's grade using GitLab's API. The result is wrapped in an - * option, where `Future(None)` indicates either: - * - the student is not registered to the class - * - the student did not push his/her solution to GitLab - */ - def getGrade(sciper: Int): Future[Option[Grade]] - - /** Retrieve the list of enrolled students from IS-academia - */ - def getScipers(): Future[List[Int]] diff --git a/previous-exams/2021-final-solutions/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala b/previous-exams/2021-final-solutions/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala deleted file mode 100644 index a67b2ad6ba95a7e5c8d0ad8a9a6e49decabad698..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala +++ /dev/null @@ -1,97 +0,0 @@ -package concpar21final01 - -import play.api.test.* -import play.api.test.Helpers.* -import scala.concurrent.duration.* -import scala.concurrent.Future -import scala.concurrent.ExecutionContext.Implicits.global - -class Problem1Suite extends munit.FunSuite: - test( - "Retrieves grades at the end of the exam (everyone pushed something) (10pts)" - ) { - class Problem1Done extends Problem1: - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - Thread.sleep(100) - Some(Grade(sciper, sciper)) - } - override def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List(1, 2, 3, 4) - } - - val expected: List[Grade] = - List(Grade(1, 1.0), Grade(2, 2.0), Grade(3, 3.0), Grade(4, 4.0)) - - (new Problem1Done).leaderboard().map { grades => - assertEquals(grades.toSet, expected.toSet) - } - } - - test("Retrieves grades mid exam (some students didn't push yet) (10pts)") { - class Problem1Partial extends Problem1: - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - Thread.sleep(100) - if sciper % 2 == 0 then None - else Some(Grade(sciper, sciper)) - } - override def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List(1, 2, 3, 4) - } - - val expected: List[Grade] = - List(Grade(1, 1.0), Grade(3, 3.0)) - - (new Problem1Partial).leaderboard().map { grades => - assertEquals(grades.toSet, expected.toSet) - } - } - - test("The output list is sorted by grade (10pts)") { - (new Problem1MockData).leaderboard().map { grades => - assert(grades.size >= 176) - assert(grades.zipWithIndex.forall { case (g, i) => - grades.drop(i).forall(x => g.grade >= x.grade) - }) - } - } - - test("GitLab API calls are done in parallel (2pts)") { - var inParallel: Boolean = false - - class Problem1Par extends Problem1MockData: - var in: Boolean = false - - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - if in then inParallel = true - in = true - val out = super.getGrade(sciper) - in = false - concurrent.Await.result(out, Duration(10, SECONDS)) - } - - (new Problem1Par).leaderboard().map { grades => - assert(grades.size >= 176) - assert(inParallel) - } - } - - test("The IS-academia API is called exactly once (2pts)") { - var called: Int = 0 - - class Problem1Once extends Problem1MockData: - override def getScipers(): Future[List[Int]] = - called += 1 - super.getScipers() - - (new Problem1Once).leaderboard().map { grades => - assert(grades.size >= 176) - assert(called == 1) - } - } diff --git a/previous-exams/2021-final-solutions/concpar21final02/.gitignore b/previous-exams/2021-final-solutions/concpar21final02/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final-solutions/concpar21final02/assignment.sbt b/previous-exams/2021-final-solutions/concpar21final02/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final-solutions/concpar21final02/build.sbt b/previous-exams/2021-final-solutions/concpar21final02/build.sbt deleted file mode 100644 index 96a9785d6b52890a5ce042606aab75a6e04512ce..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/build.sbt +++ /dev/null @@ -1,23 +0,0 @@ -course := "concpar" -assignment := "concpar21final02" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -val akkaVersion = "2.6.19" -val logbackVersion = "1.2.11" -libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-actor" % akkaVersion, - "com.typesafe.akka" %% "akka-testkit" % akkaVersion, - // SLF4J backend - // See https://doc.akka.io/docs/akka/current/typed/logging.html#slf4j-backend - "ch.qos.logback" % "logback-classic" % logbackVersion -) -fork := true -javaOptions ++= Seq("-Dakka.loglevel=Error", "-Dakka.actor.debug.receive=on") - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/CourseraStudent.scala b/previous-exams/2021-final-solutions/concpar21final02/project/CourseraStudent.scala deleted file mode 100644 index 0d5da7fa7f25c17bb2a559138862b471f38788bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/CourseraStudent.scala +++ /dev/null @@ -1,212 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scala.util.{Failure, Success, Try} -import scalaj.http._ -import play.api.libs.json.{Json, JsObject, JsPath} - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(courseId: String, key: String, partId: String, itemId: String, premiumItemId: Option[String]) - - -object CourseraStudent extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import StudentTasks.autoImport._ - import MOOCSettings.autoImport._ - import autoImport._ - - override lazy val projectSettings = Seq( - submitSetting, - ) - - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - StudentTasks.scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "progfun1" => "scala-functional-programming" - case "progfun2" => "scala-functional-program-design" - case "parprog1" => "scala-parallel-programming" - case "bigdata" => "scala-spark-big-data" - case "capstone" => "scala-capstone" - case "reactive" => "scala-akka-reactive" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - StudentTasks.failSubmit() - } - - val base64Jar = StudentTasks.prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } - -} diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/MOOCSettings.scala b/previous-exams/2021-final-solutions/concpar21final02/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/StudentTasks.scala b/previous-exams/2021-final-solutions/concpar21final02/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/build.properties b/previous-exams/2021-final-solutions/concpar21final02/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/buildSettings.sbt b/previous-exams/2021-final-solutions/concpar21final02/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final-solutions/concpar21final02/project/plugins.sbt b/previous-exams/2021-final-solutions/concpar21final02/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final-solutions/concpar21final02/src/main/scala/concpar21final02/Problem2.scala b/previous-exams/2021-final-solutions/concpar21final02/src/main/scala/concpar21final02/Problem2.scala deleted file mode 100644 index 82529b14e45531ac09cd383875967df92b8ba125..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/src/main/scala/concpar21final02/Problem2.scala +++ /dev/null @@ -1,142 +0,0 @@ -package concpar21final02 - -import akka.actor.* -import scala.collection.mutable -import akka.testkit.* - -object Problem2: - - ////////////////////////////// - // NOTIFICATION SERVICE // - ////////////////////////////// - - object NotificationService: - enum Protocol: - /** Notify all registered actors */ - case NotifyAll - - /** Register the actor that sent the `Register` request */ - case Register // - /** Un-register the actor that sent the `Register` request */ - case UnRegister - - enum Responses: - /** Message sent to an actor when it is notified */ - case Notification - - /** Response sent to an actor after a `Register` or `UnRegister` */ - case Registered(registered: Boolean) - - class NotificationService extends Actor: - import NotificationService.Protocol.* - import NotificationService.Responses.* - - private val registeredUsers = mutable.Set.empty[ActorRef] - - def receive: Receive = { - - case Register => - registeredUsers += sender() - sender() ! Registered(true) - case UnRegister => - registeredUsers -= sender() - sender() ! Registered(false) - case NotifyAll => - for user <- registeredUsers do user ! Notification - } - - ///////////////////////// - // DISCORD CHANNEL // - ///////////////////////// - - object DiscordChannel: - - enum Protocol: - - /** Post a message in the channel */ - case Post(msg: String) - - /** Ask for the list of most recent posts starting from the most recent - * one. The list must have at most `limit` posts. - */ - case GetLastPosts(limit: Int) - - /** Activates the service channel using the provided notification service. - */ - case Init(notificationService: ActorRef) - - enum Responses: - - /** Response to `GetLastPosts` if active */ - case Posts(msgs: List[String]) - - /** Response after `Init` if non-active */ - case Active - - /** Response `Post` and `GetLastPosts` if non-active */ - case NotActive - - /** Response after `Init` if active */ - case AlreadyActive - - class DiscordChannel extends Actor: - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - import NotificationService.Protocol.* - - private var messages: List[String] = Nil - - def receive: Receive = nonActive - - def nonActive: Receive = { - - case Init(service) => - context.become(active(service)) - sender() ! Active - case Post(_) | GetLastPosts(_) => - sender() ! NotActive - } - - def active(notificationService: ActorRef): Receive = { - - case Post(msg) => - messages = msg :: messages - notificationService ! NotifyAll - case GetLastPosts(limit) => - sender() ! Posts(messages.take(limit)) - case Init(_) => - sender() ! AlreadyActive - } - -///////////////////////// -// DEBUG // -///////////////////////// - -/** Infrastructure to help debugging. In sbt use `run` to execute this code. The - * TestKit is an actor that can send messages and check the messages it - * receives (or not). - */ -@main def debug() = new TestKit(ActorSystem("DebugSystem")) with ImplicitSender: - import Problem2.* - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - import NotificationService.Protocol.* - import NotificationService.Responses.* - import concurrent.duration.* - - try - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - - notificationService ! NotifyAll - expectNoMessage( - 200.millis - ) // expects no message is received in the next 200 milliseconds - - notificationService ! Register - expectMsg( - 200.millis, - Registered(true) - ) // expects to receive `Registered(true)` in the next 200 milliseconds - - finally shutdown(system) diff --git a/previous-exams/2021-final-solutions/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala b/previous-exams/2021-final-solutions/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala deleted file mode 100644 index b0aa9f2c9b48a00849561f4187be5d32f07c1810..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala +++ /dev/null @@ -1,176 +0,0 @@ -package concpar21final02 - -import akka.actor.* -import akka.testkit.* -import scala.collection.mutable -import concurrent.duration.* - -import Problem2.* - -class Problem2Suite extends munit.FunSuite: - import NotificationService.Protocol.* - import NotificationService.Responses.* - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - - test("Notification register (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - } - - test("Notification register and un-register (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! Register - expectMsg(Registered(true)) - actor ! UnRegister - expectMsg(Registered(false)) - } - - test("Notification notify (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - actor ! NotifyAll - expectMsg(Notification) - actor ! NotifyAll - expectMsg(Notification) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! NotifyAll - expectNoMessage() - actor ! Register - expectMsg(Registered(true)) - actor ! NotifyAll - expectMsg(Notification) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! NotifyAll - expectNoMessage() - } - - test("NotifyAll from other actor (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - val otherActor = system.actorOf(Props[DummyActor]()) - - def notifyFormAllFromOtherActor() = - given ActorRef = otherActor - actor ! NotifyAll - - expectNoMessage() - - actor ! Register - expectMsg(Registered(true)) - - notifyFormAllFromOtherActor() - expectMsg(Notification) - } - - test("Channel init (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - } - - test("Channel post and get post (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Post("hello") - channel ! GetLastPosts(1) - expectMsg(Posts(List("hello"))) - channel ! GetLastPosts(10) - expectMsg(Posts(List("hello"))) - channel ! GetLastPosts(0) - expectMsg(Posts(Nil)) - } - - test("Channel multiple posts (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Post("hello") - channel ! Post("world") - channel ! GetLastPosts(2) - channel ! GetLastPosts(1) - channel ! Post("!") - channel ! GetLastPosts(3) - expectMsg(Posts(List("world", "hello"))) - expectMsg(Posts(List("world"))) - expectMsg(Posts(List("!", "world", "hello"))) - } - - test("Channel posts and notify (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - notificationService ! Register - expectMsg(Registered(true)) - channel ! Post("hello") - channel ! Post("world") - expectMsg(Notification) - expectMsg(Notification) - } - - test("Channel init twice (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Init(notificationService) - expectMsg(AlreadyActive) - channel ! Init(notificationService) - expectMsg(AlreadyActive) - } - - test("Channel not active (1pts)") { - new MyTestKit: - def tests() = - val channel1 = system.actorOf(Props[DiscordChannel]()) - channel1 ! Post("hello") - expectMsg(NotActive) - - val channel2 = system.actorOf(Props[DiscordChannel]()) - channel2 ! GetLastPosts(0) - expectMsg(NotActive) - } - - abstract class MyTestKit - extends TestKit(ActorSystem("TestSystem")) - with ImplicitSender: - def tests(): Unit - try tests() - finally shutdown(system) - -class DummyActor extends Actor: - def receive: Receive = { case _ => - () - } diff --git a/previous-exams/2021-final-solutions/concpar21final03/.gitignore b/previous-exams/2021-final-solutions/concpar21final03/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final-solutions/concpar21final03/assignment.sbt b/previous-exams/2021-final-solutions/concpar21final03/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final-solutions/concpar21final03/build.sbt b/previous-exams/2021-final-solutions/concpar21final03/build.sbt deleted file mode 100644 index 8bb5226e18fade955e0f76863b48e13fd98f5f8a..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/build.sbt +++ /dev/null @@ -1,11 +0,0 @@ -course := "concpar" -assignment := "concpar21final03" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/CourseraStudent.scala b/previous-exams/2021-final-solutions/concpar21final03/project/CourseraStudent.scala deleted file mode 100644 index 0d5da7fa7f25c17bb2a559138862b471f38788bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/CourseraStudent.scala +++ /dev/null @@ -1,212 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scala.util.{Failure, Success, Try} -import scalaj.http._ -import play.api.libs.json.{Json, JsObject, JsPath} - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(courseId: String, key: String, partId: String, itemId: String, premiumItemId: Option[String]) - - -object CourseraStudent extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import StudentTasks.autoImport._ - import MOOCSettings.autoImport._ - import autoImport._ - - override lazy val projectSettings = Seq( - submitSetting, - ) - - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - StudentTasks.scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "progfun1" => "scala-functional-programming" - case "progfun2" => "scala-functional-program-design" - case "parprog1" => "scala-parallel-programming" - case "bigdata" => "scala-spark-big-data" - case "capstone" => "scala-capstone" - case "reactive" => "scala-akka-reactive" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - StudentTasks.failSubmit() - } - - val base64Jar = StudentTasks.prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } - -} diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/MOOCSettings.scala b/previous-exams/2021-final-solutions/concpar21final03/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/StudentTasks.scala b/previous-exams/2021-final-solutions/concpar21final03/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/build.properties b/previous-exams/2021-final-solutions/concpar21final03/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/buildSettings.sbt b/previous-exams/2021-final-solutions/concpar21final03/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final-solutions/concpar21final03/project/plugins.sbt b/previous-exams/2021-final-solutions/concpar21final03/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala deleted file mode 100644 index 356e2a6e42f7fec83467b82b40fab6fa83bb9dcd..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala +++ /dev/null @@ -1,41 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -import scala.collection.mutable -import scala.collection.concurrent.TrieMap - -type FileName = String - -/** An API for manipulating files. */ -trait FileSystem: - /** Create a new file named `file` with the passed `content`. */ - def createFile(file: FileName, content: String): Unit - - /** If `file` exists, return its content, otherwise crashes. */ - def readFile(file: FileName): String - - /** If `file` exists, delete it, otherwise crash. */ - def deleteFile(file: FileName): Unit -end FileSystem - -/** An in-memory file system for testing purposes implemented using a Map. - * - * Every method in this class is thread-safe. - */ -class InMemoryFileSystem extends FileSystem: - val fsMap: mutable.Map[FileName, String] = TrieMap() - - def createFile(file: FileName, content: String): Unit = - assert(!fsMap.contains(file), s"$file already exists") - fsMap(file) = content - - def readFile(file: FileName): String = - fsMap.get(file) match - case Some(content) => content - case None => assert(false, s"Attempt to read non-existing $file") - - def deleteFile(file: FileName): Unit = - fsMap.remove(file) - -end InMemoryFileSystem diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/RCU.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/RCU.scala deleted file mode 100644 index 8bfe685e22528da4c61b8b711ecd25951b5401b5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/RCU.scala +++ /dev/null @@ -1,36 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -/** A synchronization mechanism allowing multiple reads to proceed concurrently - * with an update to the state. - */ -class RCU extends Monitor: - protected val latestVersion: AtomicLong = AtomicLong(0) - protected val readersVersion: ThreadMap[Long] = ThreadMap() - - /** This method must be called before accessing shared data for reading. */ - def startRead(): Unit = - assert( - !readersVersion.currentThreadHasValue, - "startRead() cannot be called multiple times without an intervening stopRead()" - ) - readersVersion.setCurrentThreadValue(latestVersion.get) - - /** Once a thread which has previously called `startRead` has finished reading - * shared data, it must call this method. - */ - def stopRead(): Unit = - assert( - readersVersion.currentThreadHasValue, - "stopRead() cannot be called without a preceding startRead()" - ) - readersVersion.deleteCurrentThreadValue() - - /** Wait until all reads started before this method was called have finished, - * then return. - */ - def waitForOldReads(): Unit = - - val newVersion = latestVersion.incrementAndGet() - readersVersion.waitForall(_ >= newVersion) diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala deleted file mode 100644 index f58426f8507b1601aff2d52446aa2ca6f780455d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala +++ /dev/null @@ -1,55 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -import scala.collection.mutable - -/** A map which associates every thread to at most one value of type A. - * - * Every method in this class is thread-safe. - */ -class ThreadMap[A] extends Monitor: - protected val theMap: mutable.Map[Thread, A] = mutable.Map() - - /** Return the value in the map entry for the current thread if it exists, - * otherwise None. - */ - def currentThreadValue: Option[A] = synchronized { - theMap.get(Thread.currentThread) - } - - /** Is there a map entry for the current thread? */ - def currentThreadHasValue: Boolean = - - synchronized { - theMap.contains(Thread.currentThread) - } - - /** Set the map entry of the current thread to `value` and notify any thread - * waiting on `waitForall`. - */ - def setCurrentThreadValue(value: A): Unit = - - synchronized { - theMap(Thread.currentThread) = value - notifyAll() - } - - /** Delete the map entry associated with this thread (if it exists) and notify - * all threads waiting in `waitForall`. - */ - def deleteCurrentThreadValue(): Unit = - - synchronized { - theMap.remove(Thread.currentThread) - notifyAll() - } - - /** Wait until `predicate` returns true for all map entries, then return. */ - def waitForall(predicate: A => Boolean): Unit = - - synchronized { - while !theMap.forall((_, value) => predicate(value)) do wait() - } - -end ThreadMap diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala deleted file mode 100644 index 9a6c59fedd2f112ad1dc6fa98784b951c7baaee4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala +++ /dev/null @@ -1,46 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -class UpdateServer(fs: FileSystem) extends Monitor: - val rcu = new RCU - - /** The name of the file containing the latest update. - * - * This is `@volatile` to guarantee that `fetchUpdate` always sees the latest - * filename. - */ - @volatile private var updateFile: Option[FileName] = None - - /** Return the content of the latest update if one is available, otherwise - * None. - * - * This method is thread-safe. - */ - def fetchUpdate(): Option[String] = - // TODO: use `rcu` - - rcu.startRead() - val value = updateFile.map(fs.readFile) - rcu.stopRead() - value - - /** Define a new update, more precisely this will: - * - Create a new update file called `newName` with content `newContent` - * - Ensure that any future call to `fetchUpdate` returns the new update - * content. - * - Delete the old update file. - * - * This method is _NOT_ thread-safe, it cannot be safely called from multiple - * threads at once. - */ - def newUpdate(newName: FileName, newContent: String): Unit = - // TODO: use `rcu` - val oldFile = updateFile - fs.createFile(newName, newContent) - updateFile = Some(newName) - - rcu.waitForOldReads() - oldFile.foreach(fs.deleteFile) - -end UpdateServer diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala deleted file mode 100644 index 83389517581463c2a6a3895ef9a82611ef723bbe..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala +++ /dev/null @@ -1,34 +0,0 @@ -package concpar21final03.instrumentation - -/** A long value that may be updated atomically. */ -class AtomicLong(initial: Long): - - private val atomic = new java.util.concurrent.atomic.AtomicLong(initial) - - /** Get the current value. */ - def get: Long = atomic.get() - - /** Set to the given `value`. */ - def set(value: Long): Unit = atomic.set(value) - - /** Atomically increment by one the current value and return the _original_ - * value. - */ - def getAndIncrement(): Long = - atomic.getAndIncrement() - - /** Atomically increment by one the current value and return the _updated_ - * value. - */ - def incrementAndGet(): Long = - atomic.incrementAndGet() - - /** Atomically set the value to `newValue` if the current value == `expected`. - * - * Return true if successful, otherwise return false to indicate that the - * actual value was not equal to the expected value. - */ - def compareAndSet(expected: Long, newValue: Long): Boolean = - atomic.compareAndSet(expected, newValue) - -end AtomicLong diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala b/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala deleted file mode 100644 index ac6f6d2b25276a007b75d042ad8a81be7b620c51..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala +++ /dev/null @@ -1,22 +0,0 @@ -package concpar21final03.instrumentation - -class Dummy - -trait Monitor: - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overridden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala deleted file mode 100644 index f4b0b8ff6d8255dafcd3244bd974956adea8a467..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala +++ /dev/null @@ -1,118 +0,0 @@ -package concpar21final03 - -import scala.annotation.tailrec -import scala.concurrent.* -import scala.concurrent.duration.* -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation.* -import instrumentation.TestHelper.* -import instrumentation.TestUtils.* - -class Problem3Suite extends munit.FunSuite: - - test("Part 1: ThreadMap (3pts)") { - testManySchedules( - 4, - sched => - val tmap = new SchedulableThreadMap[Int](sched) - - def writeThread(): Unit = - tmap.setCurrentThreadValue(0) - tmap.setCurrentThreadValue(-1) - val readBack = tmap.currentThreadValue - assertEquals(readBack, Some(-1)) - - def writeAndDeleteThread(): Unit = - tmap.setCurrentThreadValue(42) - tmap.deleteCurrentThreadValue() - - @tailrec - def waitThread(): Unit = - tmap.waitForall(_ < 0) - val all = tmap.allValues - if all != List(-1) then waitThread() - - val threads = List( - () => writeThread(), - () => writeAndDeleteThread(), - () => waitThread(), - () => waitThread() - ) - - (threads, _ => (true, "")) - ) - } - - test("Part 2: RCU (5pts)") { - testManySchedules( - 3, - sched => - val rcu = new SchedulableRCU(sched) - - case class State( - value: Int, - isDeleted: AtomicLong = SchedulableAtomicLong(0, sched, "isDeleted") - ) - - val sharedState = - SchedulableAtomicReference(State(0), sched, "sharedState") - - def readThread(): Unit = - rcu.startRead() - val state = sharedState.get - val stateWasDeleted = state.isDeleted.get != 0 - assert( - !stateWasDeleted, - "RCU shared state deleted in the middle of a read." - ) - rcu.stopRead() - - def writeThread(): Unit = - val oldState = sharedState.get - sharedState.set(State(oldState.value + 1)) - rcu.waitForOldReads() - oldState.isDeleted.set(1) - - val threads = List( - () => readThread(), - () => readThread(), - () => writeThread() - ) - - (threads, _ => (true, "")) - ) - } - - test("Part 3: UpdateServer (2pts)") { - testManySchedules( - 3, - sched => - val fs = SchedulableInMemoryFileSystem(sched) - val server = new SchedulableUpdateServer(sched, fs) - - def writeThread(): Unit = - server.newUpdate("update1.bin", "Update 1") - server.newUpdate("update2.bin", "Update 2") - assertEquals(fs.fsMap.toSet, Set("update2.bin" -> "Update 2")) - - def fetchThread(): Unit = - val res = server.fetchUpdate() - assert( - List(None, Some("Update 1"), Some("Update 2")).contains(res), - s"fetchUpdate returned unexpected value $res" - ) - - val threads = List( - () => writeThread(), - () => fetchThread(), - () => fetchThread() - ) - - (threads, _ => (true, "")) - ) - } - - import scala.concurrent.duration.* - override val munitTimeout = 200.seconds -end Problem3Suite diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala deleted file mode 100644 index 784e02a4f5f197e7a8e1e518e81b267299ae5adc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala +++ /dev/null @@ -1,10 +0,0 @@ -package concpar21final03.instrumentation - -class AtomicReference[T](initial: T): - - private val atomic = - new java.util.concurrent.atomic.AtomicReference[T](initial) - - def get: T = atomic.get() - - def set(value: T): Unit = atomic.set(value) diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala deleted file mode 100644 index af27165bc0e22a3f8e9e5940f8ec045b42951ac2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package concpar21final03.instrumentation - -trait MockedMonitor extends Monitor: - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - override def synchronizedDefault[T](toExecute: => T): T = - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync( - this, - prevLocks - ) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try toExecute - finally - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - override def notifyDefault() = - scheduler mapOtherStates { state => - state match - case Wait(lockToAquire, locks) if lockToAquire == this => - SyncUnique(this, state.locks) - case e => e - } - scheduler.log("notify") - override def notifyAllDefault() = - scheduler mapOtherStates { state => - state match - case Wait(lockToAquire, locks) if lockToAquire == this => - Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => - Sync(this, state.locks) - case e => e - } - scheduler.log("notifyAll") - -trait LockFreeMonitor extends Monitor: - override def waitDefault() = - throw new Exception("Please use lock-free structures and do not use wait()") - override def synchronizedDefault[T](toExecute: => T): T = - throw new Exception( - "Please use lock-free structures and do not use synchronized()" - ) - override def notifyDefault() = - throw new Exception( - "Please use lock-free structures and do not use notify()" - ) - override def notifyAllDefault() = - throw new Exception( - "Please use lock-free structures and do not use notifyAll()" - ) - -abstract class ThreadState: - def locks: Seq[AnyRef] -trait CanContinueIfAcquiresLock extends ThreadState: - def lockToAquire: AnyRef -case object Start extends ThreadState: - def locks: Seq[AnyRef] = Seq.empty -case object End extends ThreadState: - def locks: Seq[AnyRef] = Seq.empty -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) - extends ThreadState - with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) - extends ThreadState - with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala deleted file mode 100644 index 3a82787deb0703497771f9efd42927a48fb981e8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala +++ /dev/null @@ -1,318 +0,0 @@ -package concpar21final03.instrumentation - -import java.util.concurrent.*; -import scala.concurrent.duration.* -import scala.collection.mutable.* -import Stats.* - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) - extends Result -case class Timeout(msg: String) extends Result - -/** A class that maintains schedule and a set of thread ids. The schedules are - * advanced after an operation of a SchedulableBuffer is performed. Note: the - * real schedule that is executed may deviate from the input schedule due to - * the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]): - val maxOps = - 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = - ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** Runs a set of operations in parallel as per the schedule. Each operation - * may consist of many primitive operations like reads or writes to shared - * data structure each of which should be executed using the function `exec`. - * @timeout - * in milliseconds - * @return - * true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { case (op, i) => - new Thread( - new Runnable(): - def run(): Unit = - val fakeId = i + 1 - setThreadId(fakeId) - try - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if completed.incrementAndGet() == ops.length then - syncObject.synchronized { syncObject.notifyAll() } - catch - case e: Throwable - if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some( - Except( - s"Thread $fakeId crashed on the following schedule: \n" + opLog - .mkString("\n"), - e.getStackTrace - ) - ) - syncObject.synchronized { syncObject.notifyAll() } - // println(s"$fakeId: ${e.toString}") - // Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - ) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if completed.get() != ops.length then syncObject.wait(timeout) } { - time => remTime -= time - } - } - if exception.isDefined then exception.get - else if remTime <= 1 - then // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - else - // every thing executed normally - RetVal(threadRes.toList) - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match - case Sync(lockToAquire, locks) => - if locks.indexOf(lockToAquire) < 0 then waitForTurn - else - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - - def waitStart(): Unit = - // while (threadStates.size < numThreads) { - // Thread.sleep(1) - // } - synchronized { - if threadStates.size < numThreads then wait() - else notifyAll() - } - - def threadLocks = - synchronized { - threadStates(threadId).locks - } - - def threadState = - synchronized { - threadStates(threadId) - } - - def mapOtherStates(f: ThreadState => ThreadState) = - val exception = threadId - synchronized { - for k <- threadStates.keys if k != exception do - threadStates(k) = f(threadStates(k)) - } - - def log(str: String) = - if (realToFakeThreadId contains Thread.currentThread().getId()) then - val space = (" " * ((threadId - 1) * 2)) - val s = - space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - - /** Executes a read or write operation to a global data structure as per the - * given schedule - * @param msg - * a message corresponding to the operation that will be logged - */ - def exec[T]( - primop: => T - )(msg: => String, postMsg: => Option[T => String] = None): T = - if !(realToFakeThreadId contains Thread.currentThread().getId()) then primop - else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if m != "" then log(m) - if opLog.size > maxOps then - throw new Exception( - s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!" - ) - val res = primop - postMsg match - case Some(m) => log(m(res)) - case None => - res - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try realToFakeThreadId(Thread.currentThread().getId()) - catch - case e: NoSuchElementException => - throw new Exception( - "You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!" - ) - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = - val tid = threadId - canContinue match - case Some((i, state)) if i == tid => - // println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match - case Sync(lockToAquire, locks) => - updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match - case SyncUnique(lockToAquire2, locks2) - if lockToAquire2 == lockToAquire => - Wait(lockToAquire2, locks2) - case e => e - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - true - case Some((i, state)) => - // println(s"$tid: not my turn but $i !") - false - case None => - false - - var threadPreference = - 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = - if !threadStates.isEmpty - then // The last thread who enters the decision loop takes the decision. - // println(s"$threadId: I'm taking a decision") - if threadStates.values.forall { - case e: Wait => true - case _ => false - } - then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - throw new Exception( - s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them." - ) - else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = - threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => - !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if threadsNotBlocked.isEmpty then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => - state.locks.map(lock => (lock, id)) - }.toMap - val reason = threadStates - .collect { - case (id, state: CanContinueIfAcquiresLock) - if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - } - .mkString("\n") - throw new Exception( - s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason" - ) - else if threadsNotBlocked.size == 1 - then // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - else { - val next = schedule.indexWhere(t => - threadsNotBlocked.exists { case (id, state) => id == t } - ) - if next != -1 then - // println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule( - next - ) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked( - threadPreference - ) // Maybe another strategy - Some(chosenOne) - // threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - else canContinue - - /** This will be called before a schedulable operation begins. This should not - * use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - // var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = - None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = - synchronized { - if numThreadsWaiting.incrementAndGet() == threadStates.size then - canContinue = decide() - notifyAll() - // waitingForDecision(threadId) = Some(numThreadsWaiting) - // println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while !canProceed() do wait() - } - numThreadsWaiting.decrementAndGet() - - /** To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - // println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if numThreadsWaiting.get() == threadStates.size then - canContinue = decide() - notifyAll() - } - - def getOperationLog() = opLog diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala deleted file mode 100644 index 455db032e2ade71dab13037e9ad14144f76b988f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package concpar21final03.instrumentation - -import java.lang.management.* - -/** A collection of methods that can be used to collect run-time statistics - * about Leon programs. This is mostly used to test the resources properties of - * Leon programs - */ -object Stats: - def timed[T](code: => T)(cont: Long => Unit): T = - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - - def withTime[T](code: => T): (T, Long) = - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala deleted file mode 100644 index 1698dcd39bffa2cabb826b34be05ebf5728ea60d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala +++ /dev/null @@ -1,147 +0,0 @@ -package concpar21final03.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map as MutableMap} - -import Stats.* - -object TestHelper: - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = - 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = - 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T]( - ops: Scheduler => Any - )(assertions: T => (Boolean, String)) = - testManySchedules( - 1, - (sched: Scheduler) => - ( - List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T]) - ) - ) - - /** @numThreads - * number of threads - * @ops - * operations to be executed, one per thread - * @assertion - * as condition that will executed after all threads have completed - * (without exceptions) the arguments are the results of the threads - */ - def testManySchedules( - numThreads: Int, - ops: Scheduler => ( - List[() => Any], // Threads - List[Any] => (Boolean, String) - ) // Assertion - ) = - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - // (1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules - .takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0) - .foreach { - // case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - // println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if threadOps.size != numThreads then - throw new IllegalStateException( - s"Number of threads: $numThreads, do not match operations of threads: $threadOps" - ) - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => - timeout -= t - } match - case Timeout(msg) => - throw new java.lang.AssertionError( - "assertion failed\n" + "The schedule took too long to complete. A possible deadlock! \n" + msg - ) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n" + stkTrace - .map(" at " + _.toString) - .mkString("\n") - throw new java.lang.AssertionError( - "assertion failed\n" + msg + "\n" + traceStr - ) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if !success then - val msg = - "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr - .getOperationLog() - .mkString("\n") - throw new java.lang.AssertionError("Assertion failed: " + msg) - } - if timeout <= 0 then - throw new java.lang.AssertionError( - "Test took too long to complete! Cannot check all schedules as your code is too slow!" - ) - - /** A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int): - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = - var contextSwitches = 0 - var contexts = - List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => - (i, readWritesPerThread) - ) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** Updates remainingOps and liveThreads once a thread is chosen for a - * position in the schedule - */ - def updateState(tid: Int): Unit = - val remOps = remainingOps(tid) - if remOps == 0 then liveThreads -= tid - else remainingOps += (tid -> (remOps - 1)) - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match - case prev :: tail - if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - updateState(tid) - acc :+ tid - case ( - acc, - _ - ) => // here context-bound has been reached so complete the schedule without any more context switches - if !contexts.isEmpty then - contexts = contexts.dropWhile(remainingOps(_) == 0) - val tid = contexts match - case top :: tail => top - case _ => - liveThreads( - 0 - ) // here, there has to be threads that have not even started - updateState(tid) - acc :+ tid - } - schedule #:: schedules() diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala deleted file mode 100644 index 0c9534b81cd3123661c6767df378422fb8a0c959..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala +++ /dev/null @@ -1,14 +0,0 @@ -package concpar21final03.instrumentation - -import scala.concurrent.* -import scala.concurrent.duration.* -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils: - def failsOrTimesOut[T](action: => T): Boolean = - val asyncAction = Future { - action - } - try Await.result(asyncAction, 2000.millisecond) - catch case _: Throwable => return true - return false diff --git a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/overrides.scala b/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/overrides.scala deleted file mode 100644 index dd9c8b9a985d04ca38fe169e573a9aee0db86010..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final-solutions/concpar21final03/src/test/scala/concpar21final03/overrides.scala +++ /dev/null @@ -1,100 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -class SchedulableThreadMap[A](val scheduler: Scheduler) - extends ThreadMap[A] - with MockedMonitor: - - override def currentThreadHasValue: Boolean = scheduler.exec { - super.currentThreadHasValue - }("", Some(res => s"currentThreadHasValue is $res")) - - override def currentThreadValue: Option[A] = scheduler.exec { - super.currentThreadValue - }("", Some(res => s"currentThreadValue is $res")) - - override def setCurrentThreadValue(value: A): Unit = scheduler.exec { - super.setCurrentThreadValue(value) - }(s"setCurrentThreadValue($value)") - - override def deleteCurrentThreadValue(): Unit = scheduler.exec { - super.deleteCurrentThreadValue() - }("deleteCurrentThreadValue()") - - override def waitForall(predicate: A => Boolean): Unit = scheduler.exec { - super.waitForall(predicate) - }("waitForall") - - def allValues: List[A] = synchronized { - theMap.values.toList - } - -end SchedulableThreadMap - -class SchedulableRCU(scheduler: Scheduler) extends RCU with LockFreeMonitor: - override protected val latestVersion = - SchedulableAtomicLong(0, scheduler, "latestVersion") - override protected val readersVersion: ThreadMap[Long] = SchedulableThreadMap( - scheduler - ) - -class SchedulableInMemoryFileSystem(scheduler: Scheduler) - extends InMemoryFileSystem: - override def createFile(file: FileName, content: String): Unit = - scheduler.exec { - super.createFile(file, content) - }(s"createFile($file)") - override def readFile(file: FileName): String = scheduler.exec { - super.readFile(file) - }(s"readFile($file)") - override def deleteFile(file: FileName): Unit = scheduler.exec { - super.deleteFile(file) - }(s"deleteFile($file)") - -class SchedulableUpdateServer(scheduler: Scheduler, fs: InMemoryFileSystem) - extends UpdateServer(fs) - with LockFreeMonitor: - override val rcu = SchedulableRCU(scheduler) - -class SchedulableAtomicLong(initial: Long, scheduler: Scheduler, name: String) - extends AtomicLong(initial): - - override def get: Long = scheduler.exec { - super.get - }(s"", Some(res => s"$name: get $res")) - - override def set(value: Long): Unit = scheduler.exec { - super.set(value) - }(s"$name: set $value", None) - - override def incrementAndGet(): Long = scheduler.exec { - super.incrementAndGet() - }(s"", Some(res => s"$name: incrementAndGet $res")) - - override def getAndIncrement(): Long = scheduler.exec { - super.getAndIncrement() - }(s"", Some(res => s"$name: getandIncrement $res")) - - override def compareAndSet(expected: Long, newValue: Long): Boolean = - scheduler.exec { - super.compareAndSet(expected, newValue) - }( - s"$name: compareAndSet(expected = $expected, newValue = $newValue)", - Some(res => s"$name: Did it set? $res") - ) - -end SchedulableAtomicLong - -class SchedulableAtomicReference[T]( - initial: T, - scheduler: Scheduler, - name: String -) extends AtomicReference(initial): - override def get: T = scheduler.exec { - super.get - }(s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - super.set(value) - }(s"$name: set $value", None) diff --git a/previous-exams/2021-final/concpar21final01.md b/previous-exams/2021-final/concpar21final01.md deleted file mode 100644 index 582f003c0744a6364b88921f0786ef74293ecc9c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01.md +++ /dev/null @@ -1,55 +0,0 @@ -# Problem 1: Futures - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar21final01 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar21final01 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Useful links - - * [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) - * [The API documentation of the Play framework](https://www.playframework.com/documentation/2.8.x/api/scala/index.html) - -## Exercise - -In this exercise, your task is to implement a leaderboard webpage for a GitLab-based exam. This leaderboard is live in the sense that it is constructed on the fly by extracting grades directly from GitLab pipelines: it is always up to date. - -This exercise uses the Play framework, a popular web application framework. -Play is entirely asynchronous and uses futures for concurrency. - -In `src/main/scala/concpar21final01/MyComponents.scala`, we define a minimal Play application to display the leaderboard (you do not need to modify this file). - -You can start this application using `sbt run` and open the leaderboard in a web browser at [http://localhost:9000/](http://localhost:9000/). After having completed this exercise, you should see a populated leaderboard as shown in this screenshot: - - - -In this exercise, your task is to implement the `leaderboard()` method in `src/main/scala/concpar21final01/Problem1.scala` which asynchronously retrieves and sorts student grades. -Grades should be sorted such that maximum grades appear at the head of the list, like in the screenshot above. -Your implementation should use the following two methods to get the list of students and the grade of a particular student: - -```scala -/** Retrieve a student's grade using GitLab's API */ -def getGrade(sciper: Int): Future[Option[Grade]] - -/** Retrieve the list of enrolled students from IS-academia */ -def getScipers(): Future[List[Int]] -``` - -These methods have mock implementations that return made-up values after a short delay (simulating a network call). -Your implementation should be asynchronous (it is forbidden to use the `Await.result` method). -Furthermore, given the large number of students, calls to the GitLab API should be made in parallel such that the overall request is completed in about 1 second. - -*Hint:* this exercise can be solved without writing any recursive functions! You are allowed to use every function defined on [Future][1] and [List][2], as well as functions defined on their companion objects ([Future][3], [List][4]). - -[1]: https://www.scala-lang.org/api/2.13.4/scala/concurrent/Future.html -[2]: https://www.scala-lang.org/api/2.13.4/scala/collection/immutable/List.html -[3]: https://www.scala-lang.org/api/2.13.4/scala/concurrent/Future$.html -[4]: https://www.scala-lang.org/api/2.13.4/scala/collection/immutable/List$.html diff --git a/previous-exams/2021-final/concpar21final01/.gitignore b/previous-exams/2021-final/concpar21final01/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final/concpar21final01/assignment.sbt b/previous-exams/2021-final/concpar21final01/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final/concpar21final01/build.sbt b/previous-exams/2021-final/concpar21final01/build.sbt deleted file mode 100644 index 8296da33001986056a2bf7795d99dff74bd23000..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/build.sbt +++ /dev/null @@ -1,19 +0,0 @@ -course := "concpar" -assignment := "concpar21final01" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -enablePlugins(PlayScala) -disablePlugins(PlayLayoutPlugin) - -libraryDependencies := libraryDependencies.value.map(dep => - if(dep.organization == "com.typesafe.play") dep.cross(CrossVersion.for3Use2_13) - else dep -) - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final/concpar21final01/grading-tests.jar b/previous-exams/2021-final/concpar21final01/grading-tests.jar deleted file mode 100644 index 2255720b53c706abe7d3e1ee9e84a52e54380075..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final/concpar21final01/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-final/concpar21final01/project/MOOCSettings.scala b/previous-exams/2021-final/concpar21final01/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final/concpar21final01/project/StudentTasks.scala b/previous-exams/2021-final/concpar21final01/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final/concpar21final01/project/build.properties b/previous-exams/2021-final/concpar21final01/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final/concpar21final01/project/buildSettings.sbt b/previous-exams/2021-final/concpar21final01/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final/concpar21final01/project/plugins.sbt b/previous-exams/2021-final/concpar21final01/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final/concpar21final01/src/main/resources/application.conf b/previous-exams/2021-final/concpar21final01/src/main/resources/application.conf deleted file mode 100644 index b2f71b4b890ae4198c93f926848ce4a13d4eb801..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/src/main/resources/application.conf +++ /dev/null @@ -1 +0,0 @@ -play.application.loader=concpar21final01.MyApplicationLoader diff --git a/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala b/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala deleted file mode 100644 index 5b960ec66c0344e9f0751d02523c5b1a47e5e519..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/MyComponents.scala +++ /dev/null @@ -1,92 +0,0 @@ -package concpar21final01 - -import play.api.{ApplicationLoader, BuiltInComponentsFromContext} -import play.api.mvc.Results.Ok -import play.api.routing.sird.* -import play.api.routing.Router -import play.api.ApplicationLoader.Context -import play.filters.HttpFiltersComponents - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future -import scala.util.Random - -class MyApplicationLoader extends ApplicationLoader: - def load(context: Context) = - new MyComponents(context).application - -class MyComponents(context: Context) - extends BuiltInComponentsFromContext(context) - with HttpFiltersComponents: - - lazy val router = Router.from { case GET(p"/") => - Action.async { - (new Problem1MockData) - .leaderboard() - .map(leaderboardHTML) - .map(Ok(_).as("text/html")) - } - } - - def leaderboardHTML(data: List[Grade]): String = - s""" - |<!DOCTYPE html> - |<html> - | <head> - | <title>Leaderboard</title> - | </head> - | <body> - | <h1>Leaderboard:</h1> - | <ul> - | ${data - .map { case Grade(sciper, g) => - val grade = "%1.2f".format(g) - s"<li>$sciper : $grade</li>" - } - .mkString("\n ")} - | </ul> - | </body> - |</html> - """.trim.stripMargin - -class Problem1MockData extends Problem1: - def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - // In an actual implementation, this is where we would make a call to - // the GitLab APIs. This mock returns a random grade after a short delay. - Thread.sleep(15) // GitLab is pretty fast today... - val rand = new Random(sciper) - val grade = rand.nextInt(6).toDouble + rand.nextDouble() - if sciper < 100000 || sciper > 999999 || sciper % 10 == 0 then None - else Some(Grade(sciper, grade)) - } - - /** Retrieve the list of enrolled students from IS-academia - */ - def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List( // A fake list of SCIPER numbers - 301425, 207372, 320658, 300217, 224523, 301068, 331020, 331095, 320270, - 320742, 299310, 300974, 322202, 343357, 302632, 343366, 320229, 269364, - 320004, 321830, 219188, 300834, 320992, 299237, 298016, 300397, 269857, - 300492, 300481, 279254, 320967, 300443, 300329, 300305, 331158, 310402, - 279067, 300682, 259825, 351616, 310869, 301215, 299481, 269375, 351249, - 310866, 351141, 301530, 361378, 351661, 351524, 311081, 331137, 332319, - 301045, 300393, 300308, 310889, 310064, 310841, 351333, 310382, 333887, - 333837, 320832, 321397, 351691, 269125, 312732, 351546, 301783, 351698, - 310775, 331388, 311139, 301992, 301578, 361760, 351174, 310298, 300666, - 259778, 301554, 301278, 301669, 321372, 311347, 321129, 351490, 321189, - 301336, 341560, 331220, 331129, 333927, 279186, 310596, 299135, 279226, - 310507, 269049, 300309, 341524, 351143, 300785, 310612, 320338, 259980, - 269952, 310397, 320246, 310959, 301454, 301835, 301802, 301649, 301170, - 301908, 351708, 321046, 361490, 311070, 351830, 311054, 311912, 301913, - 361232, 301030, 351723, 311472, 311166, 321057, 310793, 269462, 311948, - 321693, 321056, 361765, 301453, 321626, 341490, 320892, 269871, 269580, - 320199, 320908, 320830, 269071, 380542, 253768, 311204, 269127, 351073, - 341327, 301792, 299789, 361424, 301525, 311637, 321423, 279111, 330126, - 310371, 259888, 269525, 299585, 300147, 341402, 330067, 311796, 279037, - 248517, 301436, 269965, 259963, 320720, 248583, 259709, 361204, 341500, - 311803, 299981, 311832, 301088, 259649, 279183, 341760, 311844, 279079, - 390997, 311917, 390999, 361122, 301208, 311538, 272943, 361570, 390959) - } diff --git a/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/Problem1.scala b/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/Problem1.scala deleted file mode 100644 index d5a4333dfaac13a9e467f67b28bceecfa4d1f4a8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/src/main/scala/concpar21final01/Problem1.scala +++ /dev/null @@ -1,24 +0,0 @@ -package concpar21final01 - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.Future - -case class Grade(sciper: Int, grade: Double) - -trait Problem1: - /** Retrieve the list of student grades, sorted such that maximum grades - * appear at the head of the list. - */ - def leaderboard(): Future[List[Grade]] = - Future(Nil) // TODO - - /** Retrieve a student's grade using GitLab's API. The result is wrapped in an - * option, where `Future(None)` indicates either: - * - the student is not registered to the class - * - the student did not push his/her solution to GitLab - */ - def getGrade(sciper: Int): Future[Option[Grade]] - - /** Retrieve the list of enrolled students from IS-academia - */ - def getScipers(): Future[List[Int]] diff --git a/previous-exams/2021-final/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala b/previous-exams/2021-final/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala deleted file mode 100644 index a67b2ad6ba95a7e5c8d0ad8a9a6e49decabad698..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final01/src/test/scala/concpar21final01/Problem1Suite.scala +++ /dev/null @@ -1,97 +0,0 @@ -package concpar21final01 - -import play.api.test.* -import play.api.test.Helpers.* -import scala.concurrent.duration.* -import scala.concurrent.Future -import scala.concurrent.ExecutionContext.Implicits.global - -class Problem1Suite extends munit.FunSuite: - test( - "Retrieves grades at the end of the exam (everyone pushed something) (10pts)" - ) { - class Problem1Done extends Problem1: - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - Thread.sleep(100) - Some(Grade(sciper, sciper)) - } - override def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List(1, 2, 3, 4) - } - - val expected: List[Grade] = - List(Grade(1, 1.0), Grade(2, 2.0), Grade(3, 3.0), Grade(4, 4.0)) - - (new Problem1Done).leaderboard().map { grades => - assertEquals(grades.toSet, expected.toSet) - } - } - - test("Retrieves grades mid exam (some students didn't push yet) (10pts)") { - class Problem1Partial extends Problem1: - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - Thread.sleep(100) - if sciper % 2 == 0 then None - else Some(Grade(sciper, sciper)) - } - override def getScipers(): Future[List[Int]] = - Future { - Thread.sleep(100) - List(1, 2, 3, 4) - } - - val expected: List[Grade] = - List(Grade(1, 1.0), Grade(3, 3.0)) - - (new Problem1Partial).leaderboard().map { grades => - assertEquals(grades.toSet, expected.toSet) - } - } - - test("The output list is sorted by grade (10pts)") { - (new Problem1MockData).leaderboard().map { grades => - assert(grades.size >= 176) - assert(grades.zipWithIndex.forall { case (g, i) => - grades.drop(i).forall(x => g.grade >= x.grade) - }) - } - } - - test("GitLab API calls are done in parallel (2pts)") { - var inParallel: Boolean = false - - class Problem1Par extends Problem1MockData: - var in: Boolean = false - - override def getGrade(sciper: Int): Future[Option[Grade]] = - Future { - if in then inParallel = true - in = true - val out = super.getGrade(sciper) - in = false - concurrent.Await.result(out, Duration(10, SECONDS)) - } - - (new Problem1Par).leaderboard().map { grades => - assert(grades.size >= 176) - assert(inParallel) - } - } - - test("The IS-academia API is called exactly once (2pts)") { - var called: Int = 0 - - class Problem1Once extends Problem1MockData: - override def getScipers(): Future[List[Int]] = - called += 1 - super.getScipers() - - (new Problem1Once).leaderboard().map { grades => - assert(grades.size >= 176) - assert(called == 1) - } - } diff --git a/previous-exams/2021-final/concpar21final02.md b/previous-exams/2021-final/concpar21final02.md deleted file mode 100644 index f5498d50b390aaa351e5f3e8bf6544252d89b717..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02.md +++ /dev/null @@ -1,85 +0,0 @@ -# Problem 2: Actors - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar21final02 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar21final02 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## 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) - -## Exercise - -Your task is to implement a couple of actors in Discord like service. You will only focus on two actors in the system: (1) the `NotificationService` and (2) and a `DiscordChannel`. - -A user will be able to post messages on the channel and retrieve the messages from the channel. -A user also has the ability to (un)register from the notifications. -Before it can receive requests, each channel is initialized with a notification service. -When a message is posted to the channel, it tells its notification service to notify the users. - -The following diagram shows how the communication between actors works. Requests are within `()` and responses are within `[]`. - -```none - (Post) [Active] - (GetLastPosts) ┏━━━━━━━━━━━━━━━━━━┓ [AlreadyActive] ┏━━━━━━━━━┓ - ┌──────────────────────>┃ ┃──────────────────►┃ ┃ - │ ┃ DiscordChannel ┃ ┃ System ┃ - │ ┃ ┃◄──────────────────┨ ┃ - │ [Posts] ┗━┯━━━━━━━━━━━━━━━┯┛ (Init) ┗━━━━━━━━━┛ - ┏━━┷━━━┓ [NotActive] │ │ - ┃ ┃◄────────────────────┘ │ - ┃ User ┃ │ - ┃ ┃◄────────────────┐ │ - ┗━━┯━━━┛ [Registered] │ │ (NotifyAll) - │ [Notification] │ │ - │ │ │ - │ ┏━━━━┷━━━━━━━━━━━━━━━━┓ │ - └───────────────►┃ ┃ │ - (Register) ┃ NotificationService ┃◄─┘ - (UnRegister) ┃ ┃ - ┗━━━━━━━━━━━━━━━━━━━━━┛ -``` - -Your tasks in the exercise will be to: - -TASK 1: Complete the implementation of the `NotificationService` by implementing method `receive` to handle messages from `NotificationService.Protocol`: - -```scala -def receive: Receive = ??? -``` -TASK 2: Complete the implementation of the `DiscordChannel` by implementing methods `nonActive` and `active` to handle messages from `DiscordChannel.Protocol`: - -```scala -def nonActive: Receive = ??? -def active(notificationService: ActorRef): Receive = ??? -``` - -### NotificationService protocol - -* __Register__: Registers the user for notifications and responds with a `Registered(true)`. -* __UnRegister__: Un-registers the user for notifications and responds with a `Registered(false)`. -* __NotifyAll__: Sends a `Notification` to all registered users. - - -### DiscordService protocol - -The channel can be in one of two states: _non-active_ or _active_. - -* __Init__: When _non-active_, responds with `Active` and the state becomes _active_. Otherwise responds `AlreadyActive`. -* __Post__: When _active_, stores the message and sends `NotifyAll` to its `NotificationService`. Otherwise responds `NotActive`. -* __GetLastPosts__: When _active_, responds with `Posts` containing the latest messages (ordered from most to least recent). Otherwise responds `NotActive`. - -### Running the code - -Apart from the grading tests, we include a `@main def debug` method, where you can write your own tests to help you debug your implementation. This method is __not__ graded. It can be executed using `run` within SBT. diff --git a/previous-exams/2021-final/concpar21final02/.gitignore b/previous-exams/2021-final/concpar21final02/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final/concpar21final02/assignment.sbt b/previous-exams/2021-final/concpar21final02/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final/concpar21final02/build.sbt b/previous-exams/2021-final/concpar21final02/build.sbt deleted file mode 100644 index 96a9785d6b52890a5ce042606aab75a6e04512ce..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/build.sbt +++ /dev/null @@ -1,23 +0,0 @@ -course := "concpar" -assignment := "concpar21final02" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -val akkaVersion = "2.6.19" -val logbackVersion = "1.2.11" -libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-actor" % akkaVersion, - "com.typesafe.akka" %% "akka-testkit" % akkaVersion, - // SLF4J backend - // See https://doc.akka.io/docs/akka/current/typed/logging.html#slf4j-backend - "ch.qos.logback" % "logback-classic" % logbackVersion -) -fork := true -javaOptions ++= Seq("-Dakka.loglevel=Error", "-Dakka.actor.debug.receive=on") - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final/concpar21final02/grading-tests.jar b/previous-exams/2021-final/concpar21final02/grading-tests.jar deleted file mode 100644 index 82a28509efd88c52aa0924e8aaf95870abe1ccd1..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final/concpar21final02/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-final/concpar21final02/project/MOOCSettings.scala b/previous-exams/2021-final/concpar21final02/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final/concpar21final02/project/StudentTasks.scala b/previous-exams/2021-final/concpar21final02/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final/concpar21final02/project/build.properties b/previous-exams/2021-final/concpar21final02/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final/concpar21final02/project/buildSettings.sbt b/previous-exams/2021-final/concpar21final02/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final/concpar21final02/project/plugins.sbt b/previous-exams/2021-final/concpar21final02/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final/concpar21final02/src/main/scala/concpar21final02/Problem2.scala b/previous-exams/2021-final/concpar21final02/src/main/scala/concpar21final02/Problem2.scala deleted file mode 100644 index 6ff0d97e55b56cf61dcabbdfddcc61a6447412ed..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/src/main/scala/concpar21final02/Problem2.scala +++ /dev/null @@ -1,118 +0,0 @@ -package concpar21final02 - -import akka.actor.* -import scala.collection.mutable -import akka.testkit.* - -object Problem2: - - ////////////////////////////// - // NOTIFICATION SERVICE // - ////////////////////////////// - - object NotificationService: - enum Protocol: - /** Notify all registered actors */ - case NotifyAll - - /** Register the actor that sent the `Register` request */ - case Register // - /** Un-register the actor that sent the `Register` request */ - case UnRegister - - enum Responses: - /** Message sent to an actor when it is notified */ - case Notification - - /** Response sent to an actor after a `Register` or `UnRegister` */ - case Registered(registered: Boolean) - - class NotificationService extends Actor: - import NotificationService.Protocol.* - import NotificationService.Responses.* - - def receive: Receive = { - case _ => // TODO: handle messages from NotificationService.Protocol - } - - ///////////////////////// - // DISCORD CHANNEL // - ///////////////////////// - - object DiscordChannel: - - enum Protocol: - - /** Post a message in the channel */ - case Post(msg: String) - - /** Ask for the list of most recent posts starting from the most recent - * one. The list must have at most `limit` posts. - */ - case GetLastPosts(limit: Int) - - /** Activates the service channel using the provided notification service. - */ - case Init(notificationService: ActorRef) - - enum Responses: - - /** Response to `GetLastPosts` if active */ - case Posts(msgs: List[String]) - - /** Response after `Init` if non-active */ - case Active - - /** Response `Post` and `GetLastPosts` if non-active */ - case NotActive - - /** Response after `Init` if active */ - case AlreadyActive - - class DiscordChannel extends Actor: - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - import NotificationService.Protocol.* - - def receive: Receive = nonActive - - def nonActive: Receive = { - case _ => // TODO: handle messages from DiscordChannel.Protocol - } - - def active(notificationService: ActorRef): Receive = { - case _ => // TODO: handle messages from DiscordChannel.Protocol - } - -///////////////////////// -// DEBUG // -///////////////////////// - -/** Infrastructure to help debugging. In sbt use `run` to execute this code. The - * TestKit is an actor that can send messages and check the messages it - * receives (or not). - */ -@main def debug() = new TestKit(ActorSystem("DebugSystem")) with ImplicitSender: - import Problem2.* - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - import NotificationService.Protocol.* - import NotificationService.Responses.* - import concurrent.duration.* - - try - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - - notificationService ! NotifyAll - expectNoMessage( - 200.millis - ) // expects no message is received in the next 200 milliseconds - - notificationService ! Register - expectMsg( - 200.millis, - Registered(true) - ) // expects to receive `Registered(true)` in the next 200 milliseconds - - finally shutdown(system) diff --git a/previous-exams/2021-final/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala b/previous-exams/2021-final/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala deleted file mode 100644 index b0aa9f2c9b48a00849561f4187be5d32f07c1810..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final02/src/test/scala/concpar21final02/Problem2Suite.scala +++ /dev/null @@ -1,176 +0,0 @@ -package concpar21final02 - -import akka.actor.* -import akka.testkit.* -import scala.collection.mutable -import concurrent.duration.* - -import Problem2.* - -class Problem2Suite extends munit.FunSuite: - import NotificationService.Protocol.* - import NotificationService.Responses.* - import DiscordChannel.Protocol.* - import DiscordChannel.Responses.* - - test("Notification register (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - } - - test("Notification register and un-register (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! Register - expectMsg(Registered(true)) - actor ! UnRegister - expectMsg(Registered(false)) - } - - test("Notification notify (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - actor ! Register - expectMsg(Registered(true)) - actor ! NotifyAll - expectMsg(Notification) - actor ! NotifyAll - expectMsg(Notification) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! NotifyAll - expectNoMessage() - actor ! Register - expectMsg(Registered(true)) - actor ! NotifyAll - expectMsg(Notification) - actor ! UnRegister - expectMsg(Registered(false)) - actor ! NotifyAll - expectNoMessage() - } - - test("NotifyAll from other actor (1pts)") { - new MyTestKit: - def tests() = - val actor = system.actorOf(Props[NotificationService]()) - val otherActor = system.actorOf(Props[DummyActor]()) - - def notifyFormAllFromOtherActor() = - given ActorRef = otherActor - actor ! NotifyAll - - expectNoMessage() - - actor ! Register - expectMsg(Registered(true)) - - notifyFormAllFromOtherActor() - expectMsg(Notification) - } - - test("Channel init (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - } - - test("Channel post and get post (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Post("hello") - channel ! GetLastPosts(1) - expectMsg(Posts(List("hello"))) - channel ! GetLastPosts(10) - expectMsg(Posts(List("hello"))) - channel ! GetLastPosts(0) - expectMsg(Posts(Nil)) - } - - test("Channel multiple posts (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Post("hello") - channel ! Post("world") - channel ! GetLastPosts(2) - channel ! GetLastPosts(1) - channel ! Post("!") - channel ! GetLastPosts(3) - expectMsg(Posts(List("world", "hello"))) - expectMsg(Posts(List("world"))) - expectMsg(Posts(List("!", "world", "hello"))) - } - - test("Channel posts and notify (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - notificationService ! Register - expectMsg(Registered(true)) - channel ! Post("hello") - channel ! Post("world") - expectMsg(Notification) - expectMsg(Notification) - } - - test("Channel init twice (1pts)") { - new MyTestKit: - def tests() = - val notificationService = system.actorOf(Props[NotificationService]()) - val channel = system.actorOf(Props[DiscordChannel]()) - channel ! Init(notificationService) - expectMsg(Active) - channel ! Init(notificationService) - expectMsg(AlreadyActive) - channel ! Init(notificationService) - expectMsg(AlreadyActive) - } - - test("Channel not active (1pts)") { - new MyTestKit: - def tests() = - val channel1 = system.actorOf(Props[DiscordChannel]()) - channel1 ! Post("hello") - expectMsg(NotActive) - - val channel2 = system.actorOf(Props[DiscordChannel]()) - channel2 ! GetLastPosts(0) - expectMsg(NotActive) - } - - abstract class MyTestKit - extends TestKit(ActorSystem("TestSystem")) - with ImplicitSender: - def tests(): Unit - try tests() - finally shutdown(system) - -class DummyActor extends Actor: - def receive: Receive = { case _ => - () - } diff --git a/previous-exams/2021-final/concpar21final03.md b/previous-exams/2021-final/concpar21final03.md deleted file mode 100644 index 0954e94b4dad3ea21afa3f5d27ab8c5dd209caa1..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03.md +++ /dev/null @@ -1,161 +0,0 @@ -# Problem 3: Concurrency - -## Setup - -Use the following commands to make a fresh clone of your repository: - -``` -git clone -b concpar21final03 git@gitlab.epfl.ch:lamp/student-repositories-s22/cs206-GASPAR.git concpar21final03 -``` - -If you have issues with the IDE, try [reimporting the -build](https://gitlab.epfl.ch/lamp/cs206/-/blob/master/labs/example-lab.md#troubleshooting), -if you still have problems, use `compile` in sbt instead. - -## Useful links - - * [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) - -## Problem description -### Preliminary: File handling - -In this exercise, we will work with files using the following trait to handle -all file operations: -```scala -type FileName = String -trait FileSystem: - /** Create a new file named `file` with the passed `content`. */ - def createFile(file: File, content: String): Unit - /** If `file` exists, return its content, otherwise crash. */ - def readFile(file: File): String - /** If `file` exists, delete it, otherwise crash. */ - def deleteFile(file: File): Unit -``` -Note that to make testing easier, the actual implementation of `FileSystem` we will use -won't actually create files on disks, instead it will simply use a `Map` to -represent files and their content in memory, but that's an implementation detail -that won't affect how this exercise should be solved. - -### The update distribution problem - -You work at a game company on the popular online game EPFNite™. Your job is -to distribute game updates to the players from the update server represented by -the following class: -```scala -class UpdateServer: - def fetchUpdate(): Option[String] - def newUpdate(newName: FileName, newContent: String): Unit -``` -The requirements of the update server are as follows: -- When a player starts his game, it connects to the update server which starts a - new thread and run `fetchUpdate()` which should return the content of the latest game update - if one is available. -- When a new version of the game is available, the developers call - `newUpdate` with the name of the update file and its content. -- Storage space is limited on the server, so when a new update is stored on the - server, old ones must be deleted. - -Based on these requirements, you come up with the following implementation: - -```scala -class UpdateServer(fs: FileSystem): - @volatile private var updateFile: Option[FileName] = None - - def fetchUpdate(): Option[String] = - updateFile.map(fs.readFile) - - def newUpdate(newName: FileName, newContent: String): Unit = - val oldFile = updateFile - fs.createFile(newName, newContent) - updateFile = Some(newName) - oldFile.foreach(fs.deleteFile) -``` -Unfortunately, it turns out that reading a file is not an atomic operation: if -you delete a file while another thread is reading it, your program crashes. -Theoretically, you could solve this using locks to make sure `deleteFile` -is never called at the same time as `readFile`, but this solution isn't good -enough for EPFNite: it's important that a player is never blocked from playing -the game because `fetchUpdate` is waiting for a lock to become available. - -Thankfully, there is one property of the problem which we can take advantage of: -a call to `fetchUpdate` which happens *after* `updateFile = Some(newName)` will -read the new file and not the old one, so all we need to do is to wait until all -calls to `fetchUpdate` which were started *before* we mutated `updateFile` have -finished before calling `deleteFile`. It turns out that there exists one -mechanism to do this efficiently: **RCU** (Read-copy-update) which you will implement in the next -section. - -## Implementation -### Part 1: Complete the `ThreadMap` implementation - -To implement RCU we will need a thread-safe way to associate a value to a -thread: this is the job of `ThreadMap` (defined in `ThreadMap.scala`) which we -implement with a `Map` whose keys are instances of `Thread` -(`Thread.currentThread` can be used to retrieve the instance for the current -thread). - -Instead of the usual `forall` method on collections, `ThreadMap` has a -`waitForall` method which will **block** until all entries of the map return -true for the predicate. For example given `val m: ThreadMap[Int]`, if one thread -runs: -```scala -m.setCurrentThread(1) -``` -and another thread runs: -```scala -m.waitForall(_ < 0) -``` -Then the second thread will be blocked, but if the first thread then runs: -```scala -m.setCurrentThread(-1) -``` -The second thread will be immediately unblocked. - -Your first task is to **implement all methods in `ThreadMap.scala` whose body is -currently `???`.** Once you're done, the "Part 1" test will pass. - -### Part 2: Complete the `RCU` implementation - -#### What is RCU ? - -The RCU API defines three methods: - -```scala -class RCU: - def startRead(): Unit - def stopRead(): Unit - def waitForOldReads(): Unit -``` - -It has the following contract: -- The first two methods are meant to be used by threads that read shared data: - they must must call `startRead` *before* reading shared data, then call - `stopRead` once they're done reading. -- `waitForOldReaders()` can be called from any thread: this is a blocking method - that only returns when all reads started *before* the call to - `waitForOldReaders()` are stopped (new reads may have started since then). - -#### Implementing RCU - -To implement RCU we need a way to differentiate reads started before a call to -`waitForOldReaders()` from those started after. To do so we will use *version -numbers*: the RCU version (starting at 0) is stored in `latestVersion`, and for -each *active* reader thread, we remember the value of `latestVersion` *at the time -startRead() was called* in `readersVersion`. Implementing `waitForOldReaders` is -then easy: -1. Increment the RCU version. -2. Wait until there's no active reader associated with a previous version. - -**Implement `waitForOldReaders` in `RCU.scala`**, for simplicity you can assume -that `waitForOldReaders` will never be called from multiple threads at once. -Once you're done, the "Part 2" test will pass. - -### Part 3: Using RCU in `UpdateServer` - -Finally, its time to put our RCU implementation to good use: **complete the -implementation of `fetchUpdate` and `newUpdate`** (defined in `UpdateServer.scala`) by adding calls to -`rcu.startRead()`, `rcu.stopRead()` and `rcu.waitForOldReaders()` where they -need to be to allow multiple calls to `fetchUpdate` and at most one call to -`newUpdate` to be run concurrently. Once you're done, the "Part 3" test will -pass. diff --git a/previous-exams/2021-final/concpar21final03/.gitignore b/previous-exams/2021-final/concpar21final03/.gitignore deleted file mode 100644 index d094868cd9b4b92462501f0510a8bf72881ec542..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.DS_Store -*.swp -*~ -*.class -*.tasty -target/ -logs/ -.bloop -.bsp -.dotty-ide-artifact -.dotty-ide.json -.idea -.metals -.vscode -*.csv -*.dat -metals.sbt diff --git a/previous-exams/2021-final/concpar21final03/assignment.sbt b/previous-exams/2021-final/concpar21final03/assignment.sbt deleted file mode 100644 index d38b4f897512c8645042d6a12a0c33c5584828c3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/assignment.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) - -assignmentVersion.withRank(KeyRanks.Invisible) := "eadbf7a6" - diff --git a/previous-exams/2021-final/concpar21final03/build.sbt b/previous-exams/2021-final/concpar21final03/build.sbt deleted file mode 100644 index 8bb5226e18fade955e0f76863b48e13fd98f5f8a..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/build.sbt +++ /dev/null @@ -1,11 +0,0 @@ -course := "concpar" -assignment := "concpar21final03" -scalaVersion := "3.1.0" - -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") -libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M3" % Test - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") diff --git a/previous-exams/2021-final/concpar21final03/grading-tests.jar b/previous-exams/2021-final/concpar21final03/grading-tests.jar deleted file mode 100644 index 3b501477800dae895a5df8f435005a1a8b804d9b..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final/concpar21final03/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-final/concpar21final03/project/MOOCSettings.scala b/previous-exams/2021-final/concpar21final03/project/MOOCSettings.scala deleted file mode 100644 index 347cc6e5d59073cf532986c82151cbc44887108f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/project/MOOCSettings.scala +++ /dev/null @@ -1,51 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val datasetUrl = settingKey[String]("URL of the dataset used for testing") - val downloadDataset = taskKey[File]("Download the dataset required for the assignment") - val assignmentVersion = settingKey[String]("Hash string indicating the version of the assignment") - } - - import autoImport._ - - lazy val downloadDatasetDef = downloadDataset := { - val logger = streams.value.log - - datasetUrl.?.value match { - case Some(url) => - - import scalaj.http.Http - import sbt.io.IO - val dest = (Compile / resourceManaged).value / assignment.value / url.split("/").last - if (!dest.exists()) { - IO.touch(dest) - logger.info(s"Downloading $url") - val res = Http(url).method("GET") - val is = res.asBytes.body - IO.write(dest, is) - } - dest - case None => - logger.info(s"No dataset defined in datasetUrl") - throw new sbt.MessageOnlyException("No dataset to download for this assignment") - } - } - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - downloadDatasetDef, - Test / parallelExecution := false, - // Report test result after each test instead of waiting for every test to finish - Test / logBuffered := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-final/concpar21final03/project/StudentTasks.scala b/previous-exams/2021-final/concpar21final03/project/StudentTasks.scala deleted file mode 100644 index 1ae03c11516a13a55e094a936b02fed588c2a9e2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/project/StudentTasks.scala +++ /dev/null @@ -1,150 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ -import scalafix.sbt.ScalafixPlugin.autoImport._ - -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - - val packageSubmission = inputKey[Unit]("package solution as an archive file") - lazy val Grading = config("grading") extend(Runtime) - } - - import autoImport._ - - // Run scalafix linting after compilation to avoid seeing parser errors twice - // Keep in sync with the use of scalafix in Grader - // (--exclude doesn't work (https://github.com/lampepfl-courses/moocs/pull/28#issuecomment-427894795) - // so we customize unmanagedSources below instead) - val scalafixLinting = Def.taskDyn { - if (new File(".scalafix.conf").exists()) { - (Compile / scalafix).toTask(" --check").dependsOn(Compile / compile) - } else Def.task(()) - } - - val testsJar = file("grading-tests.jar") - - override lazy val projectSettings = Seq( - // Run scalafix linting in parallel with the tests - (Test / test) := { - scalafixLinting.value - (Test / test).value - }, - - packageSubmissionSetting, - - fork := true, - run / connectInput := true, - outputStrategy := Some(StdoutOutput), - scalafixConfig := { - val scalafixDotConf = (baseDirectory.value / ".scalafix.conf") - if (scalafixDotConf.exists) Some(scalafixDotConf) else None - } - ) ++ packageSubmissionZipSettings ++ ( - if(testsJar.exists) inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += testsJar, - definedTests := (Test / definedTests).value, - internalDependencyClasspath := (Test / internalDependencyClasspath).value, - managedClasspath := (Test / managedClasspath).value, - )) - else Nil - ) - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (Compile / packageSourcesOnly).value - val binaries = (Compile / packageBinWithoutResources).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - packageSourcesOnly / artifactClassifier := Some("sources"), - Compile / packageBinWithoutResources / artifact ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (Compile / resources).value.flatMap(Path.relativeTo((Compile / resourceDirectories).value)(_)) - (Compile / packageBin / mappings).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (Compile / packageSubmissionZip).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-final/concpar21final03/project/build.properties b/previous-exams/2021-final/concpar21final03/project/build.properties deleted file mode 100644 index 3161d2146c631009a4d731d13510aeaddc9cf47e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.6.1 diff --git a/previous-exams/2021-final/concpar21final03/project/buildSettings.sbt b/previous-exams/2021-final/concpar21final03/project/buildSettings.sbt deleted file mode 100644 index 1d987356b002ed0ad6c32492aa0bf2532370edf7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.15" \ No newline at end of file diff --git a/previous-exams/2021-final/concpar21final03/project/plugins.sbt b/previous-exams/2021-final/concpar21final03/project/plugins.sbt deleted file mode 100644 index 3c7aad8964d825963f87341033685db13d1000d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.26") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala deleted file mode 100644 index 356e2a6e42f7fec83467b82b40fab6fa83bb9dcd..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/FileSystem.scala +++ /dev/null @@ -1,41 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -import scala.collection.mutable -import scala.collection.concurrent.TrieMap - -type FileName = String - -/** An API for manipulating files. */ -trait FileSystem: - /** Create a new file named `file` with the passed `content`. */ - def createFile(file: FileName, content: String): Unit - - /** If `file` exists, return its content, otherwise crashes. */ - def readFile(file: FileName): String - - /** If `file` exists, delete it, otherwise crash. */ - def deleteFile(file: FileName): Unit -end FileSystem - -/** An in-memory file system for testing purposes implemented using a Map. - * - * Every method in this class is thread-safe. - */ -class InMemoryFileSystem extends FileSystem: - val fsMap: mutable.Map[FileName, String] = TrieMap() - - def createFile(file: FileName, content: String): Unit = - assert(!fsMap.contains(file), s"$file already exists") - fsMap(file) = content - - def readFile(file: FileName): String = - fsMap.get(file) match - case Some(content) => content - case None => assert(false, s"Attempt to read non-existing $file") - - def deleteFile(file: FileName): Unit = - fsMap.remove(file) - -end InMemoryFileSystem diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/RCU.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/RCU.scala deleted file mode 100644 index b924cacca689e78134189f2d23fbd77db7bdde6a..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/RCU.scala +++ /dev/null @@ -1,34 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -/** A synchronization mechanism allowing multiple reads to proceed concurrently - * with an update to the state. - */ -class RCU extends Monitor: - protected val latestVersion: AtomicLong = AtomicLong(0) - protected val readersVersion: ThreadMap[Long] = ThreadMap() - - /** This method must be called before accessing shared data for reading. */ - def startRead(): Unit = - assert( - !readersVersion.currentThreadHasValue, - "startRead() cannot be called multiple times without an intervening stopRead()" - ) - readersVersion.setCurrentThreadValue(latestVersion.get) - - /** Once a thread which has previously called `startRead` has finished reading - * shared data, it must call this method. - */ - def stopRead(): Unit = - assert( - readersVersion.currentThreadHasValue, - "stopRead() cannot be called without a preceding startRead()" - ) - readersVersion.deleteCurrentThreadValue() - - /** Wait until all reads started before this method was called have finished, - * then return. - */ - def waitForOldReads(): Unit = - ??? diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala deleted file mode 100644 index d01afe522674c9acf6a172e4dadf49c220782bda..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/ThreadMap.scala +++ /dev/null @@ -1,41 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -import scala.collection.mutable - -/** A map which associates every thread to at most one value of type A. - * - * Every method in this class is thread-safe. - */ -class ThreadMap[A] extends Monitor: - protected val theMap: mutable.Map[Thread, A] = mutable.Map() - - /** Return the value in the map entry for the current thread if it exists, - * otherwise None. - */ - def currentThreadValue: Option[A] = synchronized { - theMap.get(Thread.currentThread) - } - - /** Is there a map entry for the current thread? */ - def currentThreadHasValue: Boolean = - ??? - - /** Set the map entry of the current thread to `value` and notify any thread - * waiting on `waitForall`. - */ - def setCurrentThreadValue(value: A): Unit = - ??? - - /** Delete the map entry associated with this thread (if it exists) and notify - * all threads waiting in `waitForall`. - */ - def deleteCurrentThreadValue(): Unit = - ??? - - /** Wait until `predicate` returns true for all map entries, then return. */ - def waitForall(predicate: A => Boolean): Unit = - ??? - -end ThreadMap diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala deleted file mode 100644 index 5bd91a33c5374ecf1fd6bf978c525a5795a53e03..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/UpdateServer.scala +++ /dev/null @@ -1,40 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -class UpdateServer(fs: FileSystem) extends Monitor: - val rcu = new RCU - - /** The name of the file containing the latest update. - * - * This is `@volatile` to guarantee that `fetchUpdate` always sees the latest - * filename. - */ - @volatile private var updateFile: Option[FileName] = None - - /** Return the content of the latest update if one is available, otherwise - * None. - * - * This method is thread-safe. - */ - def fetchUpdate(): Option[String] = - // TODO: use `rcu` - updateFile.map(fs.readFile) - - /** Define a new update, more precisely this will: - * - Create a new update file called `newName` with content `newContent` - * - Ensure that any future call to `fetchUpdate` returns the new update - * content. - * - Delete the old update file. - * - * This method is _NOT_ thread-safe, it cannot be safely called from multiple - * threads at once. - */ - def newUpdate(newName: FileName, newContent: String): Unit = - // TODO: use `rcu` - val oldFile = updateFile - fs.createFile(newName, newContent) - updateFile = Some(newName) - oldFile.foreach(fs.deleteFile) - -end UpdateServer diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala deleted file mode 100644 index 83389517581463c2a6a3895ef9a82611ef723bbe..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/AtomicLong.scala +++ /dev/null @@ -1,34 +0,0 @@ -package concpar21final03.instrumentation - -/** A long value that may be updated atomically. */ -class AtomicLong(initial: Long): - - private val atomic = new java.util.concurrent.atomic.AtomicLong(initial) - - /** Get the current value. */ - def get: Long = atomic.get() - - /** Set to the given `value`. */ - def set(value: Long): Unit = atomic.set(value) - - /** Atomically increment by one the current value and return the _original_ - * value. - */ - def getAndIncrement(): Long = - atomic.getAndIncrement() - - /** Atomically increment by one the current value and return the _updated_ - * value. - */ - def incrementAndGet(): Long = - atomic.incrementAndGet() - - /** Atomically set the value to `newValue` if the current value == `expected`. - * - * Return true if successful, otherwise return false to indicate that the - * actual value was not equal to the expected value. - */ - def compareAndSet(expected: Long, newValue: Long): Boolean = - atomic.compareAndSet(expected, newValue) - -end AtomicLong diff --git a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala b/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala deleted file mode 100644 index ac6f6d2b25276a007b75d042ad8a81be7b620c51..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/main/scala/concpar21final03/instrumentation/Monitor.scala +++ /dev/null @@ -1,22 +0,0 @@ -package concpar21final03.instrumentation - -class Dummy - -trait Monitor: - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overridden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala deleted file mode 100644 index f4b0b8ff6d8255dafcd3244bd974956adea8a467..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/Problem3Suite.scala +++ /dev/null @@ -1,118 +0,0 @@ -package concpar21final03 - -import scala.annotation.tailrec -import scala.concurrent.* -import scala.concurrent.duration.* -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation.* -import instrumentation.TestHelper.* -import instrumentation.TestUtils.* - -class Problem3Suite extends munit.FunSuite: - - test("Part 1: ThreadMap (3pts)") { - testManySchedules( - 4, - sched => - val tmap = new SchedulableThreadMap[Int](sched) - - def writeThread(): Unit = - tmap.setCurrentThreadValue(0) - tmap.setCurrentThreadValue(-1) - val readBack = tmap.currentThreadValue - assertEquals(readBack, Some(-1)) - - def writeAndDeleteThread(): Unit = - tmap.setCurrentThreadValue(42) - tmap.deleteCurrentThreadValue() - - @tailrec - def waitThread(): Unit = - tmap.waitForall(_ < 0) - val all = tmap.allValues - if all != List(-1) then waitThread() - - val threads = List( - () => writeThread(), - () => writeAndDeleteThread(), - () => waitThread(), - () => waitThread() - ) - - (threads, _ => (true, "")) - ) - } - - test("Part 2: RCU (5pts)") { - testManySchedules( - 3, - sched => - val rcu = new SchedulableRCU(sched) - - case class State( - value: Int, - isDeleted: AtomicLong = SchedulableAtomicLong(0, sched, "isDeleted") - ) - - val sharedState = - SchedulableAtomicReference(State(0), sched, "sharedState") - - def readThread(): Unit = - rcu.startRead() - val state = sharedState.get - val stateWasDeleted = state.isDeleted.get != 0 - assert( - !stateWasDeleted, - "RCU shared state deleted in the middle of a read." - ) - rcu.stopRead() - - def writeThread(): Unit = - val oldState = sharedState.get - sharedState.set(State(oldState.value + 1)) - rcu.waitForOldReads() - oldState.isDeleted.set(1) - - val threads = List( - () => readThread(), - () => readThread(), - () => writeThread() - ) - - (threads, _ => (true, "")) - ) - } - - test("Part 3: UpdateServer (2pts)") { - testManySchedules( - 3, - sched => - val fs = SchedulableInMemoryFileSystem(sched) - val server = new SchedulableUpdateServer(sched, fs) - - def writeThread(): Unit = - server.newUpdate("update1.bin", "Update 1") - server.newUpdate("update2.bin", "Update 2") - assertEquals(fs.fsMap.toSet, Set("update2.bin" -> "Update 2")) - - def fetchThread(): Unit = - val res = server.fetchUpdate() - assert( - List(None, Some("Update 1"), Some("Update 2")).contains(res), - s"fetchUpdate returned unexpected value $res" - ) - - val threads = List( - () => writeThread(), - () => fetchThread(), - () => fetchThread() - ) - - (threads, _ => (true, "")) - ) - } - - import scala.concurrent.duration.* - override val munitTimeout = 200.seconds -end Problem3Suite diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala deleted file mode 100644 index 784e02a4f5f197e7a8e1e518e81b267299ae5adc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/AtomicReference.scala +++ /dev/null @@ -1,10 +0,0 @@ -package concpar21final03.instrumentation - -class AtomicReference[T](initial: T): - - private val atomic = - new java.util.concurrent.atomic.AtomicReference[T](initial) - - def get: T = atomic.get() - - def set(value: T): Unit = atomic.set(value) diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala deleted file mode 100644 index af27165bc0e22a3f8e9e5940f8ec045b42951ac2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package concpar21final03.instrumentation - -trait MockedMonitor extends Monitor: - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - override def synchronizedDefault[T](toExecute: => T): T = - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync( - this, - prevLocks - ) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try toExecute - finally - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - override def notifyDefault() = - scheduler mapOtherStates { state => - state match - case Wait(lockToAquire, locks) if lockToAquire == this => - SyncUnique(this, state.locks) - case e => e - } - scheduler.log("notify") - override def notifyAllDefault() = - scheduler mapOtherStates { state => - state match - case Wait(lockToAquire, locks) if lockToAquire == this => - Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => - Sync(this, state.locks) - case e => e - } - scheduler.log("notifyAll") - -trait LockFreeMonitor extends Monitor: - override def waitDefault() = - throw new Exception("Please use lock-free structures and do not use wait()") - override def synchronizedDefault[T](toExecute: => T): T = - throw new Exception( - "Please use lock-free structures and do not use synchronized()" - ) - override def notifyDefault() = - throw new Exception( - "Please use lock-free structures and do not use notify()" - ) - override def notifyAllDefault() = - throw new Exception( - "Please use lock-free structures and do not use notifyAll()" - ) - -abstract class ThreadState: - def locks: Seq[AnyRef] -trait CanContinueIfAcquiresLock extends ThreadState: - def lockToAquire: AnyRef -case object Start extends ThreadState: - def locks: Seq[AnyRef] = Seq.empty -case object End extends ThreadState: - def locks: Seq[AnyRef] = Seq.empty -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) - extends ThreadState - with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) - extends ThreadState - with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala deleted file mode 100644 index 3a82787deb0703497771f9efd42927a48fb981e8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Scheduler.scala +++ /dev/null @@ -1,318 +0,0 @@ -package concpar21final03.instrumentation - -import java.util.concurrent.*; -import scala.concurrent.duration.* -import scala.collection.mutable.* -import Stats.* - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) - extends Result -case class Timeout(msg: String) extends Result - -/** A class that maintains schedule and a set of thread ids. The schedules are - * advanced after an operation of a SchedulableBuffer is performed. Note: the - * real schedule that is executed may deviate from the input schedule due to - * the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]): - val maxOps = - 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = - ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** Runs a set of operations in parallel as per the schedule. Each operation - * may consist of many primitive operations like reads or writes to shared - * data structure each of which should be executed using the function `exec`. - * @timeout - * in milliseconds - * @return - * true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { case (op, i) => - new Thread( - new Runnable(): - def run(): Unit = - val fakeId = i + 1 - setThreadId(fakeId) - try - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if completed.incrementAndGet() == ops.length then - syncObject.synchronized { syncObject.notifyAll() } - catch - case e: Throwable - if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some( - Except( - s"Thread $fakeId crashed on the following schedule: \n" + opLog - .mkString("\n"), - e.getStackTrace - ) - ) - syncObject.synchronized { syncObject.notifyAll() } - // println(s"$fakeId: ${e.toString}") - // Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - ) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if completed.get() != ops.length then syncObject.wait(timeout) } { - time => remTime -= time - } - } - if exception.isDefined then exception.get - else if remTime <= 1 - then // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - else - // every thing executed normally - RetVal(threadRes.toList) - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match - case Sync(lockToAquire, locks) => - if locks.indexOf(lockToAquire) < 0 then waitForTurn - else - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - - def waitStart(): Unit = - // while (threadStates.size < numThreads) { - // Thread.sleep(1) - // } - synchronized { - if threadStates.size < numThreads then wait() - else notifyAll() - } - - def threadLocks = - synchronized { - threadStates(threadId).locks - } - - def threadState = - synchronized { - threadStates(threadId) - } - - def mapOtherStates(f: ThreadState => ThreadState) = - val exception = threadId - synchronized { - for k <- threadStates.keys if k != exception do - threadStates(k) = f(threadStates(k)) - } - - def log(str: String) = - if (realToFakeThreadId contains Thread.currentThread().getId()) then - val space = (" " * ((threadId - 1) * 2)) - val s = - space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - - /** Executes a read or write operation to a global data structure as per the - * given schedule - * @param msg - * a message corresponding to the operation that will be logged - */ - def exec[T]( - primop: => T - )(msg: => String, postMsg: => Option[T => String] = None): T = - if !(realToFakeThreadId contains Thread.currentThread().getId()) then primop - else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if m != "" then log(m) - if opLog.size > maxOps then - throw new Exception( - s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!" - ) - val res = primop - postMsg match - case Some(m) => log(m(res)) - case None => - res - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try realToFakeThreadId(Thread.currentThread().getId()) - catch - case e: NoSuchElementException => - throw new Exception( - "You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!" - ) - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = - val tid = threadId - canContinue match - case Some((i, state)) if i == tid => - // println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match - case Sync(lockToAquire, locks) => - updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match - case SyncUnique(lockToAquire2, locks2) - if lockToAquire2 == lockToAquire => - Wait(lockToAquire2, locks2) - case e => e - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - true - case Some((i, state)) => - // println(s"$tid: not my turn but $i !") - false - case None => - false - - var threadPreference = - 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = - if !threadStates.isEmpty - then // The last thread who enters the decision loop takes the decision. - // println(s"$threadId: I'm taking a decision") - if threadStates.values.forall { - case e: Wait => true - case _ => false - } - then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - throw new Exception( - s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them." - ) - else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = - threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => - !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if threadsNotBlocked.isEmpty then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => - state.locks.map(lock => (lock, id)) - }.toMap - val reason = threadStates - .collect { - case (id, state: CanContinueIfAcquiresLock) - if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - } - .mkString("\n") - throw new Exception( - s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason" - ) - else if threadsNotBlocked.size == 1 - then // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - else { - val next = schedule.indexWhere(t => - threadsNotBlocked.exists { case (id, state) => id == t } - ) - if next != -1 then - // println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule( - next - ) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked( - threadPreference - ) // Maybe another strategy - Some(chosenOne) - // threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - else canContinue - - /** This will be called before a schedulable operation begins. This should not - * use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - // var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = - None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = - synchronized { - if numThreadsWaiting.incrementAndGet() == threadStates.size then - canContinue = decide() - notifyAll() - // waitingForDecision(threadId) = Some(numThreadsWaiting) - // println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while !canProceed() do wait() - } - numThreadsWaiting.decrementAndGet() - - /** To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - // println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if numThreadsWaiting.get() == threadStates.size then - canContinue = decide() - notifyAll() - } - - def getOperationLog() = opLog diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala deleted file mode 100644 index 455db032e2ade71dab13037e9ad14144f76b988f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/Stats.scala +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package concpar21final03.instrumentation - -import java.lang.management.* - -/** A collection of methods that can be used to collect run-time statistics - * about Leon programs. This is mostly used to test the resources properties of - * Leon programs - */ -object Stats: - def timed[T](code: => T)(cont: Long => Unit): T = - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - - def withTime[T](code: => T): (T, Long) = - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala deleted file mode 100644 index 1698dcd39bffa2cabb826b34be05ebf5728ea60d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestHelper.scala +++ /dev/null @@ -1,147 +0,0 @@ -package concpar21final03.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map as MutableMap} - -import Stats.* - -object TestHelper: - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = - 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = - 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T]( - ops: Scheduler => Any - )(assertions: T => (Boolean, String)) = - testManySchedules( - 1, - (sched: Scheduler) => - ( - List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T]) - ) - ) - - /** @numThreads - * number of threads - * @ops - * operations to be executed, one per thread - * @assertion - * as condition that will executed after all threads have completed - * (without exceptions) the arguments are the results of the threads - */ - def testManySchedules( - numThreads: Int, - ops: Scheduler => ( - List[() => Any], // Threads - List[Any] => (Boolean, String) - ) // Assertion - ) = - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - // (1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules - .takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0) - .foreach { - // case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - // println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if threadOps.size != numThreads then - throw new IllegalStateException( - s"Number of threads: $numThreads, do not match operations of threads: $threadOps" - ) - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => - timeout -= t - } match - case Timeout(msg) => - throw new java.lang.AssertionError( - "assertion failed\n" + "The schedule took too long to complete. A possible deadlock! \n" + msg - ) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n" + stkTrace - .map(" at " + _.toString) - .mkString("\n") - throw new java.lang.AssertionError( - "assertion failed\n" + msg + "\n" + traceStr - ) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if !success then - val msg = - "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr - .getOperationLog() - .mkString("\n") - throw new java.lang.AssertionError("Assertion failed: " + msg) - } - if timeout <= 0 then - throw new java.lang.AssertionError( - "Test took too long to complete! Cannot check all schedules as your code is too slow!" - ) - - /** A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int): - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = - var contextSwitches = 0 - var contexts = - List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => - (i, readWritesPerThread) - ) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** Updates remainingOps and liveThreads once a thread is chosen for a - * position in the schedule - */ - def updateState(tid: Int): Unit = - val remOps = remainingOps(tid) - if remOps == 0 then liveThreads -= tid - else remainingOps += (tid -> (remOps - 1)) - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match - case prev :: tail - if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - updateState(tid) - acc :+ tid - case ( - acc, - _ - ) => // here context-bound has been reached so complete the schedule without any more context switches - if !contexts.isEmpty then - contexts = contexts.dropWhile(remainingOps(_) == 0) - val tid = contexts match - case top :: tail => top - case _ => - liveThreads( - 0 - ) // here, there has to be threads that have not even started - updateState(tid) - acc :+ tid - } - schedule #:: schedules() diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala deleted file mode 100644 index 0c9534b81cd3123661c6767df378422fb8a0c959..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/instrumentation/TestUtils.scala +++ /dev/null @@ -1,14 +0,0 @@ -package concpar21final03.instrumentation - -import scala.concurrent.* -import scala.concurrent.duration.* -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils: - def failsOrTimesOut[T](action: => T): Boolean = - val asyncAction = Future { - action - } - try Await.result(asyncAction, 2000.millisecond) - catch case _: Throwable => return true - return false diff --git a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/overrides.scala b/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/overrides.scala deleted file mode 100644 index dd9c8b9a985d04ca38fe169e573a9aee0db86010..0000000000000000000000000000000000000000 --- a/previous-exams/2021-final/concpar21final03/src/test/scala/concpar21final03/overrides.scala +++ /dev/null @@ -1,100 +0,0 @@ -package concpar21final03 - -import instrumentation.* - -class SchedulableThreadMap[A](val scheduler: Scheduler) - extends ThreadMap[A] - with MockedMonitor: - - override def currentThreadHasValue: Boolean = scheduler.exec { - super.currentThreadHasValue - }("", Some(res => s"currentThreadHasValue is $res")) - - override def currentThreadValue: Option[A] = scheduler.exec { - super.currentThreadValue - }("", Some(res => s"currentThreadValue is $res")) - - override def setCurrentThreadValue(value: A): Unit = scheduler.exec { - super.setCurrentThreadValue(value) - }(s"setCurrentThreadValue($value)") - - override def deleteCurrentThreadValue(): Unit = scheduler.exec { - super.deleteCurrentThreadValue() - }("deleteCurrentThreadValue()") - - override def waitForall(predicate: A => Boolean): Unit = scheduler.exec { - super.waitForall(predicate) - }("waitForall") - - def allValues: List[A] = synchronized { - theMap.values.toList - } - -end SchedulableThreadMap - -class SchedulableRCU(scheduler: Scheduler) extends RCU with LockFreeMonitor: - override protected val latestVersion = - SchedulableAtomicLong(0, scheduler, "latestVersion") - override protected val readersVersion: ThreadMap[Long] = SchedulableThreadMap( - scheduler - ) - -class SchedulableInMemoryFileSystem(scheduler: Scheduler) - extends InMemoryFileSystem: - override def createFile(file: FileName, content: String): Unit = - scheduler.exec { - super.createFile(file, content) - }(s"createFile($file)") - override def readFile(file: FileName): String = scheduler.exec { - super.readFile(file) - }(s"readFile($file)") - override def deleteFile(file: FileName): Unit = scheduler.exec { - super.deleteFile(file) - }(s"deleteFile($file)") - -class SchedulableUpdateServer(scheduler: Scheduler, fs: InMemoryFileSystem) - extends UpdateServer(fs) - with LockFreeMonitor: - override val rcu = SchedulableRCU(scheduler) - -class SchedulableAtomicLong(initial: Long, scheduler: Scheduler, name: String) - extends AtomicLong(initial): - - override def get: Long = scheduler.exec { - super.get - }(s"", Some(res => s"$name: get $res")) - - override def set(value: Long): Unit = scheduler.exec { - super.set(value) - }(s"$name: set $value", None) - - override def incrementAndGet(): Long = scheduler.exec { - super.incrementAndGet() - }(s"", Some(res => s"$name: incrementAndGet $res")) - - override def getAndIncrement(): Long = scheduler.exec { - super.getAndIncrement() - }(s"", Some(res => s"$name: getandIncrement $res")) - - override def compareAndSet(expected: Long, newValue: Long): Boolean = - scheduler.exec { - super.compareAndSet(expected, newValue) - }( - s"$name: compareAndSet(expected = $expected, newValue = $newValue)", - Some(res => s"$name: Did it set? $res") - ) - -end SchedulableAtomicLong - -class SchedulableAtomicReference[T]( - initial: T, - scheduler: Scheduler, - name: String -) extends AtomicReference(initial): - override def get: T = scheduler.exec { - super.get - }(s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - super.set(value) - }(s"$name: set $value", None) diff --git a/previous-exams/2021-final/leaderboard.png b/previous-exams/2021-final/leaderboard.png deleted file mode 100644 index 345da3a6dfb917967344ef7546d41755623336e3..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final/leaderboard.png and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m1/.gitignore b/previous-exams/2021-midterm-solutions/m1/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m1/assignment.sbt b/previous-exams/2021-midterm-solutions/m1/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m1/build.sbt b/previous-exams/2021-midterm-solutions/m1/build.sbt deleted file mode 100644 index e4766880cca56983c63e60a86fd6e83af3750053..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m1" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m1.M1Suite" diff --git a/previous-exams/2021-midterm-solutions/m1/grading-tests.jar b/previous-exams/2021-midterm-solutions/m1/grading-tests.jar deleted file mode 100644 index 6fa91f4263cecf0bd58cfea49fefc29d3cf7bffa..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m1/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m1/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m1/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m1/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m1/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m1/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m1/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m1/project/build.properties b/previous-exams/2021-midterm-solutions/m1/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m1/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m1/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m1/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m1/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/Lib.scala b/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/Lib.scala deleted file mode 100644 index 37ce78015dfcc3dd679e238ab5bad98903b7e03c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/Lib.scala +++ /dev/null @@ -1,60 +0,0 @@ -package m1 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A fractional number representing `numerator/denominator` */ - case class Frac(numerator: Int, denominator: Int) { - def toDouble: Double = numerator.toDouble / denominator - } - - /** Tree result of an upsweep operation. Specialized for `Frac` results. */ - trait TreeRes { val res: Frac } - /** Leaf result of an upsweep operation. Specialized for `Frac` results. */ - case class Leaf(from: Int, to: Int, res: Frac) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `Frac` results. */ - case class Node(left: TreeRes, res: Frac, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/M1.scala b/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/M1.scala deleted file mode 100644 index fc5399100b3641d1d7fd3189258f4fb5e706fe7d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/src/main/scala/m1/M1.scala +++ /dev/null @@ -1,76 +0,0 @@ -package m1 - - -trait M1 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling average of array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(x1 / 1, (x1 + x2) / 2, (x1 + x2 + x3) / 3, ..., (x1 + x2 + x3 + ... + xn) / n)` - */ - def rollingAveragesParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - - val out: Arr[Double] = Arr.ofLength(arr.length) - val tree = upsweep(arr, 0, arr.length) - downsweep(arr, Frac(0, 0), tree, out) - out - } - - // No need to modify this - def scanOp(acc: Frac, x: Frac) = - Frac(acc.numerator + x.numerator, acc.denominator + x.denominator) - - - def upsweep(input: Arr[Int], from: Int, to: Int): TreeRes = { - if (to - from < THRESHOLD) - Leaf(from, to, reduceSequential(input, from + 1, to, Frac(input(from), 1))) - else { - val mid = from + (to - from)/2 - val (tL, tR) = parallel( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - - def downsweep(input: Arr[Int], a0: Frac, tree: TreeRes, output: Arr[Double]): Unit = { - tree match { - case Node(left, _, right) => - parallel( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - - def downsweepSequential(input: Arr[Int], from: Int, to: Int, a0: Frac, output: Arr[Double]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, Frac(input(i), 1)) - output(i) = a.toDouble - i = i + 1 - } - } - } - - - def reduceSequential(input: Arr[Int], from: Int, to: Int, a0: Frac): Frac = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, Frac(input(i), 1)) - i = i + 1 - } - a - } - -} diff --git a/previous-exams/2021-midterm-solutions/m1/src/test/scala/m1/M1Suite.scala b/previous-exams/2021-midterm-solutions/m1/src/test/scala/m1/M1Suite.scala deleted file mode 100644 index ab1b8652a90c04eddcf5767bc413126be1152f6e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m1/src/test/scala/m1/M1Suite.scala +++ /dev/null @@ -1,156 +0,0 @@ -package m1 - -class M1Suite extends munit.FunSuite { - - test("Rolling average result test (5pts)") { - RollingAveragesBasicLogicTest.basicTests() - RollingAveragesBasicLogicTest.normalTests() - RollingAveragesBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling average parallelism test (30pts)") { - RollingAveragesCallsToParallel.parallelismTest() - RollingAveragesParallel.basicTests() - RollingAveragesParallel.normalTests() - RollingAveragesParallel.largeTests() - } - - test("[TASK 2] Rolling average no `map` test (35pts)") { - RollingAveragesNoMap.basicTests() - RollingAveragesNoMap.normalTests() - RollingAveragesNoMap.largeTests() - } - - test("[TASK 3] Rolling average no `tail` test (30pts)") { - RollingAveragesNoTail.basicTests() - RollingAveragesNoTail.normalTests() - RollingAveragesNoTail.largeTests() - } - - - object RollingAveragesBasicLogicTest extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingAveragesCallsToParallel extends M1 with LibImpl with RollingAveragesTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingAveragesParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingAveragesNoMap extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingAveragesNoTail extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingAveragesParallel extends M1 with LibImpl with RollingAveragesTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingAveragesTest extends M1 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def basicTests() = { - assertEquals(rollingAveragesParallel(Arr()), Arr[Double]()) - assertEquals(rollingAveragesParallel(Arr(1)), Arr[Double](1)) - assertEquals(rollingAveragesParallel(Arr(1, 2, 3, 4)), Arr(1, 1.5, 2, 2.5)) - assertEquals(rollingAveragesParallel(Arr(4, 4, 4, 4)), Arr[Double](4, 4, 4, 4)) - } - - def normalTests() = { - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(64)(identity): _*)), Arr(Array.tabulate(64)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(4, 4, 4, 4)), Arr[Double](4, 4, 4, 4)) - assertEquals(rollingAveragesParallel(Arr(4, 8, 6, 4)), Arr[Double](4, 6, 6, 5.5)) - assertEquals(rollingAveragesParallel(Arr(4, 3, 2, 1)), Arr(4, 3.5, 3, 2.5)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(64)(identity).reverse: _*)), Arr(Array.tabulate(64)(i => 63 - i.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(128)(i => 128 - 2*i).reverse: _*)), Arr(Array.tabulate(128)(i => -126d + i): _*)) - } - - def largeTests() = { - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(500)(identity): _*)), Arr(Array.tabulate(500)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(512)(identity): _*)), Arr(Array.tabulate(512)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(1_000)(identity): _*)), Arr(Array.tabulate(1_000)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(10_000)(identity): _*)), Arr(Array.tabulate(10_000)(_.toDouble / 2): _*)) - } - } -} \ No newline at end of file diff --git a/previous-exams/2021-midterm-solutions/m14/.gitignore b/previous-exams/2021-midterm-solutions/m14/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m14/assignment.sbt b/previous-exams/2021-midterm-solutions/m14/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m14/build.sbt b/previous-exams/2021-midterm-solutions/m14/build.sbt deleted file mode 100644 index aeee575ac20b4770fe264f7327098c1da3387794..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m14" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m14.M14Suite" diff --git a/previous-exams/2021-midterm-solutions/m14/grading-tests.jar b/previous-exams/2021-midterm-solutions/m14/grading-tests.jar deleted file mode 100644 index ff7d9e97309ad2d12b3694244f6870f5603f0dbc..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m14/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m14/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m14/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m14/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m14/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m14/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m14/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m14/project/build.properties b/previous-exams/2021-midterm-solutions/m14/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m14/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m14/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m14/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m14/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractBlockingQueue.scala b/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractBlockingQueue.scala deleted file mode 100644 index a91a39c7ce364151f5c2aa9968de43aecc1ef984..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractBlockingQueue.scala +++ /dev/null @@ -1,14 +0,0 @@ -package m14 - -abstract class AbstractBlockingQueue[T] extends Monitor { - private var underlying: List[T] = Nil - - def getUnderlying(): List[T] = - underlying - - def setUnderlying(newValue: List[T]): Unit = - underlying = newValue - - def put(elem: T): Unit - def take(): T -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala b/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala deleted file mode 100644 index 670294c04eaa9376c25984061168a2c0ad275669..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala +++ /dev/null @@ -1,7 +0,0 @@ -package m14 - -abstract class AbstractThreadPoolExecutor { - def execute(task: Unit => Unit): Unit - def start(): Unit - def shutdown(): Unit -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/M14.scala b/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/M14.scala deleted file mode 100644 index 82e2e4c20f7dad9d3ad87588f31b2a566a31bef5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/M14.scala +++ /dev/null @@ -1,80 +0,0 @@ -package m14 - -object M14 { - /** A thread pool that executes submitted task using one of several threads */ - class ThreadPoolExecutor(taskQueue: BlockingQueue[Unit => Unit], poolSize: Int) - extends AbstractThreadPoolExecutor { - - private class Worker extends Thread { - override def run(): Unit = { - try { - while (true) { - - val task = taskQueue.take() - task(()) - } - } catch { - case e: InterruptedException => - // Nothing to do here, we are shutting down gracefully. - } - } - } - private val workers: List[Worker] = List.fill(poolSize)(new Worker()) - - /** Executes the given task, passed by name. */ - def execute(task: Unit => Unit): Unit = - - taskQueue.put(task) - - /** Starts the thread pool. */ - def start(): Unit = - workers.foreach(_.start()) - - /** Instantly shuts down all actively executing tasks using an interrupt. */ - def shutdown(): Unit = - workers.foreach(_.interrupt()) - } - - /** - * A queue whose take operations blocks until the queue become non-empty. - * Elements must be retrived from this queue in a last in, first out order. - * All methods of this class are thread safe, that is, they can safely - * be used from multiple thread without any particular synchronization. - */ - class BlockingQueue[T] extends AbstractBlockingQueue[T] { - - // The state of this queue is stored in an underlying List[T] defined in - // the AbstractBlockingQueue class. Your implementation should access and - // update this list using the following setter and getter methods: - // - def getUnderlying(): List[T] - // - def setUnderlying(newValue: List[T]): Unit - // Using these methods is required for testing purposes. - - /** Inserts the specified element into this queue (non-blocking) */ - def put(elem: T): Unit = - - this.synchronized { - val underlying = getUnderlying() - setUnderlying(elem :: underlying) - this.notifyAll() - } - - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * This queue operates in a first in, first out order. - * until an element becomes available (blocking). - * This queue operates in a last in, first out order. - */ - def take(): T = - - this.synchronized { - while (getUnderlying().isEmpty) - this.wait() - val underlying = getUnderlying() - val head = underlying.head - setUnderlying(underlying.tail) - head - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/Monitor.scala b/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/Monitor.scala deleted file mode 100644 index 97dd73a6038ef6966a899da8c6b1c7dc9c9109de..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/main/scala/m14/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m14 - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/M14Suite.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/M14Suite.scala deleted file mode 100644 index cd04f2a32971eedc0e12400ae35f88d7c8f45571..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/M14Suite.scala +++ /dev/null @@ -1,159 +0,0 @@ -package m14 - -import instrumentation.SchedulableBlockingQueue -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -class M14Suite extends munit.FunSuite { - import M14._ - - test("ThreadPool should put jobs in the queue, Workers should execute jobs from the queue (10pts)") { - case class PutE(e: Unit => Unit) extends Exception - val nThreads = 3 - var taken = false - class TestBlockingQueue extends BlockingQueue[Unit => Unit] { - override def put(e: Unit => Unit): Unit = - throw new PutE(e) - - override def take(): Unit => Unit = - x => { - taken = true - Thread.sleep(10 * 1000) - } - } - - val tpe = new ThreadPoolExecutor(new TestBlockingQueue, nThreads) - val unit2unit: Unit => Unit = x => () - try { - tpe.execute(unit2unit) - assert(false, "ThreadPoolExecutor does not put jobs in the queue") - } catch { - case PutE(e) => - assert(e == unit2unit) - } - tpe.start() - Thread.sleep(1000) - assert(taken, s"ThreadPoolExecutor workers do no execute jobs from the queue") - tpe.shutdown() - } - - test("BlockingQueue should work in a sequential setting (1pts)") { - testSequential[(Int, Int, Int, Int)]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched) - queue.put(1) - queue.put(2) - queue.put(3) - queue.put(4) - (queue.take(), - queue.take(), - queue.take(), - queue.take()) - }{ tuple => - (tuple == (4, 3, 2, 1), s"Expected (4, 3, 2, 1) got $tuple") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'take' (3pts)") { - testManySchedules(2, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.take()), - args => (args(1) == 1, s"Expected 1, got ${args(1)}")) - }) - } - - test("BlockingQueue should not be able to take from an empty queue (3pts)") { - testSequential[Boolean]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched); - queue.put(1) - queue.put(2) - queue.take() - queue.take() - failsOrTimesOut(queue.take()) - }{ res => - (res, "Was able to retrieve an element from an empty queue") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take' (5pts)") { - testManySchedules(3, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.take()) - , args => { - val takeRes = args(2).asInstanceOf[Int] - val nocreation = (takeRes == 1 || takeRes == 2) - if (!nocreation) - (false, s"'take' should return either 1 or 2") - else (true, "") - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', Thread 4: 'take' (10pts)") { - testManySchedules(4, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.take(), () => queue.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(2).asInstanceOf[Int] - val takeRes2 = args(3).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 3: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 4: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - (false, s"'Thread 3 and 4' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'put(3)', Thread 4: 'take', Thread 5: 'take' (10pts)") { - testManySchedules(5, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.put(3), - () => queue.take(), () => queue.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2, 3).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1); put(2); take', Thread 2: 'put(3)', Thread 3: 'put(4)' (10pts)") { - testManySchedules(3, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List( - () => { queue.put(1); queue.put(2); queue.take() }, - () => queue.put(3), - () => queue.put(4) - ), args => { - val takeRes = args(0).asInstanceOf[Int] - val nocreation = List(1, 2, 3, 4).contains - if (!nocreation(takeRes)) - (false, s"'Thread 1: take' returned $takeRes, but should return a value in {1, 2, 3, 4}") - else if (takeRes == 1) - (false, s"'Thread 1' returned 2 before returning 1 (got $takeRes)") - else - (true, "") - }) - }) - } -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala deleted file mode 100644 index 64aa205a5e1487a2dc0d3f6dc9f4435454a5b648..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package m14 -package instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala deleted file mode 100644 index 16e68fa913f770e7b85cee2af2bdec390cb7ee4e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala +++ /dev/null @@ -1,17 +0,0 @@ -package m14 -package instrumentation - -class SchedulableBlockingQueue[T](val scheduler: Scheduler) - extends m14.M14.BlockingQueue[T] with MockedMonitor { - private var underlying: List[T] = Nil - - override def getUnderlying(): List[T] = - scheduler.exec { - underlying - }(s"Get $underlying") - - override def setUnderlying(newValue: List[T]): Unit = - scheduler.exec { - underlying = newValue - }(s"Set $newValue") -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Scheduler.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Scheduler.scala deleted file mode 100644 index 448a8091eed701a6258b53110aef2ae17416afc8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Scheduler.scala +++ /dev/null @@ -1,305 +0,0 @@ -package m14 -package instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Stats.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Stats.scala deleted file mode 100644 index bc1241c543227a71727d2ca2987e3bdc9fed3210..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m14 -package instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestHelper.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestHelper.scala deleted file mode 100644 index faa3505b2d85e546e20f9f228ca0ad1f6ac9c438..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestHelper.scala +++ /dev/null @@ -1,125 +0,0 @@ -package m14 -package instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 240 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestUtils.scala b/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestUtils.scala deleted file mode 100644 index f980f99e34d653acde5590cb5e1e508607d3b61b..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m14/src/test/scala/m14/instrumentation/TestUtils.scala +++ /dev/null @@ -1,20 +0,0 @@ -package m14 -package instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm-solutions/m15/.gitignore b/previous-exams/2021-midterm-solutions/m15/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m15/assignment.sbt b/previous-exams/2021-midterm-solutions/m15/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m15/build.sbt b/previous-exams/2021-midterm-solutions/m15/build.sbt deleted file mode 100644 index 3b7539dcef795f03ecd7ed4ffcb5eb6839054b21..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m15" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m15.M15Suite" diff --git a/previous-exams/2021-midterm-solutions/m15/grading-tests.jar b/previous-exams/2021-midterm-solutions/m15/grading-tests.jar deleted file mode 100644 index 3243be21fe08c74418f052ef9b4f521129bd62f0..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m15/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m15/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m15/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m15/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m15/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m15/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m15/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m15/project/build.properties b/previous-exams/2021-midterm-solutions/m15/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m15/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m15/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m15/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m15/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractBlockingQueue.scala b/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractBlockingQueue.scala deleted file mode 100644 index 85a28b26c1d28327725d98d501e4f855dce0f25e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractBlockingQueue.scala +++ /dev/null @@ -1,14 +0,0 @@ -package m15 - -abstract class AbstractBlockingQueue[T] extends Monitor { - private var underlying: List[T] = Nil - - def getUnderlying(): List[T] = - underlying - - def setUnderlying(newValue: List[T]): Unit = - underlying = newValue - - def put(elem: T): Unit - def take(): T -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala b/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala deleted file mode 100644 index 5e663e8b70cd7482feca29b9791bcd766174ae49..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala +++ /dev/null @@ -1,7 +0,0 @@ -package m15 - -abstract class AbstractThreadPoolExecutor { - def execute(task: Unit => Unit): Unit - def start(): Unit - def shutdown(): Unit -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/M15.scala b/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/M15.scala deleted file mode 100644 index 27bb83d5cdf305a47500c8fddd5b146394fdc38c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/M15.scala +++ /dev/null @@ -1,79 +0,0 @@ -package m15 - -object M15 { - /** A thread pool that executes submitted task using one of several threads */ - class ThreadPoolExecutor(taskQueue: BlockingQueue[Unit => Unit], poolSize: Int) - extends AbstractThreadPoolExecutor { - - private class Worker extends Thread { - override def run(): Unit = { - try { - while (true) { - - val task = taskQueue.take() - task(()) - } - } catch { - case e: InterruptedException => - // Nothing to do here, we are shutting down gracefully. - } - } - } - private val workers: List[Worker] = List.fill(poolSize)(new Worker()) - - /** Executes the given task, passed by name. */ - def execute(task: Unit => Unit): Unit = - - taskQueue.put(task) - - /** Starts the thread pool. */ - def start(): Unit = - workers.foreach(_.start()) - - /** Instantly shuts down all actively executing tasks using an interrupt. */ - def shutdown(): Unit = - workers.foreach(_.interrupt()) - } - - /** - * A queue whose take operations blocks until the queue become non-empty. - * Elements must be retrived from this queue in a first in, first out order. - * All methods of this class are thread safe, that is, they can safely - * be used from multiple thread without any particular synchronization. - */ - class BlockingQueue[T] extends AbstractBlockingQueue[T] { - - // The state of this queue is stored in an underlying List[T] defined in - // the AbstractBlockingQueue class. Your implementation should access and - // update this list using the following setter and getter methods: - // - def getUnderlying(): List[T] - // - def setUnderlying(newValue: List[T]): Unit - // Using these methods is required for testing purposes. - - /** Inserts the specified element into this queue (non-blocking) */ - def put(elem: T): Unit = - - this.synchronized { - val underlying = getUnderlying() - setUnderlying(elem :: underlying) - this.notifyAll() - } - - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * until an element becomes available (blocking). - * This queue operates in a first in, first out order. - */ - def take(): T = - - this.synchronized { - while (getUnderlying().isEmpty) - this.wait() - val underlying = getUnderlying() - val last = underlying.last - setUnderlying(underlying.init) - last - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/Monitor.scala b/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/Monitor.scala deleted file mode 100644 index b64e697d613b2d44c3f892e4ae0eebf028b5d5e8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/main/scala/m15/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m15 - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/M15Suite.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/M15Suite.scala deleted file mode 100644 index e0f2243993c4f40b8e43b0b51e1e45b8c77d2c21..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/M15Suite.scala +++ /dev/null @@ -1,281 +0,0 @@ -package m15 - -import instrumentation.SchedulableBlockingQueue -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -class M15Suite extends munit.FunSuite { - import M15._ - - test("ThreadPool should put jobs in the queue, Workers should execute jobs from the queue (10pts)") { - case class PutE(e: Unit => Unit) extends Exception - val nThreads = 3 - var taken = false - class TestBlockingQueue extends BlockingQueue[Unit => Unit] { - override def put(e: Unit => Unit): Unit = - throw new PutE(e) - - override def take(): Unit => Unit = - x => { - taken = true - Thread.sleep(10 * 1000) - } - } - - val tpe = new ThreadPoolExecutor(new TestBlockingQueue, nThreads) - val unit2unit: Unit => Unit = x => () - try { - tpe.execute(unit2unit) - assert(false, "ThreadPoolExecutor does not put jobs in the queue") - } catch { - case PutE(e) => - assert(e == unit2unit) - } - tpe.start() - Thread.sleep(1000) - assert(taken, s"ThreadPoolExecutor workers do no execute jobs from the queue") - tpe.shutdown() - } - - test("BlockingQueue should work in a sequential setting (1pts)") { - testSequential[(Int, Int, Int, Int)]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched) - queue.put(1) - queue.put(2) - queue.put(3) - queue.put(4) - (queue.take(), - queue.take(), - queue.take(), - queue.take()) - }{ tuple => - (tuple == (1, 2, 3, 4), s"Expected (1, 2, 3, 4) got $tuple") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'take' (3pts)") { - testManySchedules(2, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.take()), - args => (args(1) == 1, s"Expected 1, got ${args(1)}")) - }) - } - - test("BlockingQueue should not be able to take from an empty queue (3pts)") { - testSequential[Boolean]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched); - queue.put(1) - queue.put(2) - queue.take() - queue.take() - failsOrTimesOut(queue.take()) - }{ res => - (res, "Was able to retrieve an element from an empty queue") - } - } - - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', and a buffer of size 1") { - testManySchedules(3, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.take()) - , args => { - val takeRes = args(2).asInstanceOf[Int] - val nocreation = (takeRes == 1 || takeRes == 2) - if (!nocreation) - (false, s"'take' should return either 1 or 2") - else (true, "") - }) - }) - } - - // testing no duplication - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', Thread 4: 'take', and a buffer of size 3") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(2).asInstanceOf[Int] - val takeRes2 = args(3).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 3: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 4: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - (false, s"'Thread 3 and 4' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - // testing no duplication with 5 threads - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'put(3)', Thread 4: 'take', Thread 5: 'take', and a buffer of size 1") { - testManySchedules(5, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.put(3), - () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2, 3).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - // testing fifo buffer size 1 - test("Should work when Thread 1: 'put(1); put(2)', Thread 2: 'take', Thread 3: 'put(3)', Thread 4: 'put(4)', and a buffer of size 3") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(2) }, () => prodCons.take(), - () => prodCons.put(3), () => prodCons.put(4)) - , args => { - def m(): (Boolean, String) = { - val takeRes = args(1).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 3, 4).contains(x) - if (!nocreation(takeRes)) - return (false, s"'Thread 2: take' returned $takeRes, but should return a value in {1, 2, 3, 4}") - // fifo (cannot have 2 without 1) - if (takeRes == 2) - (false, s"'Thread 2' returned 2 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // testing fifo buffer size 5 - test("Should work when Thread 1: 'put(1); put(2)', Thread 2: 'take', Thread 3: 'put(11)', Thread 4: 'put(10)', and a buffer of size 5") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(2) }, () => prodCons.take(), - () => prodCons.put(11), () => prodCons.put(10)) - , args => { - def m(): (Boolean, String) = { - val takeRes = args(1).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 10, 11).contains(x) - if (!nocreation(takeRes)) - return (false, s"'Thread 2: take' returned $takeRes, but should return a value in {1, 2, 10, 11}") - // fifo (cannot have 2 without 1) - if (takeRes == 2) - (false, s"'Thread 2' returned 2 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // testing fifo on more complicated case - test("Should work when Thread 1: 'put(1); put(3)', Thread 2: 'put(2)', Thread 3: 'put(4)', Thread 4: 'take', Thread 5: 'take', and a buffer of size 10") { - testManySchedules(5, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(3) }, () => prodCons.put(2), - () => prodCons.put(4), () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 3, 4).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3, 4}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3, 4}") - // no duplication - if (takeRes1 == takeRes2) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - // fifo (cannot have 3 without 1) - val takes = List(takeRes1, takeRes2) - if (takes.contains(3) && !takes.contains(1)) - (false, s"'Thread 4 or 5' returned 3 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // combining put and take in one thread - test("Should work when Thread 1: 'put(21); put(22)', Thread 2: 'take', Thread 3: 'put(23); take', Thread 4: 'put(24); take', and a buffer of size 2") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(21); prodCons.put(22) }, () => prodCons.take(), - () => { prodCons.put(23); prodCons.take() }, () => { prodCons.put(24); prodCons.take() }) - , args => { - def m(): (Boolean, String) = { - val takes = List(args(1).asInstanceOf[Int], args(2).asInstanceOf[Int], args(3).asInstanceOf[Int]) - // no creation - val vals = List(21, 22, 23, 24) - - var i = 0 - while (i < takes.length) { - val x = takes(i) - if (!vals.contains(x)) - return (false, s"'Thread $i: take' returned $x but should return a value in $vals") - i += 1 - } - - // no duplication - if (takes.distinct.size != takes.size) - return (false, s"Takes did not return unique values: $takes") - // fifo (cannot have 22 without 21) - if (takes.contains(22) && !takes.contains(21)) - (false, s"`Takes returned 22 before returning 21") - else - (true, "") - } - m() - }) - }) - } - - // completely hidden hard to crack test - test("[Black box test] Values should be taken in the order they are put") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[(Char, Int)](sched) - val n = 2 - (List( - () => for (i <- 1 to n) { prodCons.put(('a', i)) }, - () => for (i <- 1 to n) { prodCons.put(('b', i)) }, - () => for (i <- 1 to n) { prodCons.put(('c', i)) }, - () => { - import scala.collection.mutable - var counts = mutable.HashMap.empty[Char, Int] - counts('a') = 0 - counts('b') = 0 - counts('c') = 0 - for (i <- 1 to (3 * n)) { - val (c, n) = prodCons.take() - counts(c) += 1 - assert(counts(c) == n) - } - }) - , _ => - (true, "") - ) - }) - } -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala deleted file mode 100644 index c0591e3e03adc249e4a857600d20362bed219ba9..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package m15 -package instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala deleted file mode 100644 index 31b09bef249bc17111043612f069402ef13bdf4f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala +++ /dev/null @@ -1,17 +0,0 @@ -package m15 -package instrumentation - -class SchedulableBlockingQueue[T](val scheduler: Scheduler) - extends m15.M15.BlockingQueue[T] with MockedMonitor { - private var underlying: List[T] = Nil - - override def getUnderlying(): List[T] = - scheduler.exec { - underlying - }(s"Get $underlying") - - override def setUnderlying(newValue: List[T]): Unit = - scheduler.exec { - underlying = newValue - }(s"Set $newValue") -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Scheduler.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Scheduler.scala deleted file mode 100644 index fd5f427bb86376709efeebebf0dbabc1bc96e70a..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Scheduler.scala +++ /dev/null @@ -1,305 +0,0 @@ -package m15 -package instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Stats.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Stats.scala deleted file mode 100644 index e82c09813f44c824cdfa55d54d8dd00acb584b48..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m15 -package instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestHelper.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestHelper.scala deleted file mode 100644 index 5f863382c87cb808f70a3ed4aacabec1496f15c4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestHelper.scala +++ /dev/null @@ -1,125 +0,0 @@ -package m15 -package instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 240 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestUtils.scala b/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestUtils.scala deleted file mode 100644 index 3f4afe8845bff9e2608f3b2e3b92a8739ad238cc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m15/src/test/scala/m15/instrumentation/TestUtils.scala +++ /dev/null @@ -1,20 +0,0 @@ -package m15 -package instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm-solutions/m2/.gitignore b/previous-exams/2021-midterm-solutions/m2/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m2/assignment.sbt b/previous-exams/2021-midterm-solutions/m2/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m2/build.sbt b/previous-exams/2021-midterm-solutions/m2/build.sbt deleted file mode 100644 index 4a68d9e22fc13fac03309e5751f98bf7dd08349e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m2" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m2.M2Suite" diff --git a/previous-exams/2021-midterm-solutions/m2/grading-tests.jar b/previous-exams/2021-midterm-solutions/m2/grading-tests.jar deleted file mode 100644 index 66ce3fdf704542bc3d07a5b92687caf1fd2b3cf1..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m2/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m2/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m2/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m2/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m2/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m2/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m2/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m2/project/build.properties b/previous-exams/2021-midterm-solutions/m2/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m2/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m2/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m2/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m2/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/Lib.scala b/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/Lib.scala deleted file mode 100644 index 9f1aff59d87f86ee2092ec49479f388b4054a643..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/Lib.scala +++ /dev/null @@ -1,60 +0,0 @@ -package m2 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A number representing `radicand^(1.0/degree)` */ - case class Root(radicand: Int, degree: Int) { - def toDouble: Double = scala.math.pow(radicand, 1.0/degree) - } - - /** Tree result of an upsweep operation. Specialized for `Root` results. */ - trait TreeRes { val res: Root } - /** Leaf result of an upsweep operation. Specialized for `Root` results. */ - case class Leaf(from: Int, to: Int, res: Root) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `Root` results. */ - case class Node(left: TreeRes, res: Root, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/M2.scala b/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/M2.scala deleted file mode 100644 index 17109982524a19500935523c27ef03a1098065f7..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/src/main/scala/m2/M2.scala +++ /dev/null @@ -1,75 +0,0 @@ -package m2 - - -trait M2 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling geometric mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(math.pow(x1, 1), math.pow((x1 + x2), 1.0/2), math.pow((x1 + x2 + x3), 1.0/3), ..., math.pow((x1 + x2 + x3 + ... + xn), 1.0/n))` - */ - def rollingGeoMeanParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - - val out: Arr[Double] = Arr.ofLength(arr.length) - val tree = upsweep(arr, 0, arr.length) - downsweep(arr, Root(1, 0), tree, out) - out - } - - // No need to modify this - def scanOp(acc: Root, x: Root) = - Root(acc.radicand * x.radicand, acc.degree + x.degree) - - - def upsweep(input: Arr[Int], from: Int, to: Int): TreeRes = { - if (to - from < THRESHOLD) - Leaf(from, to, reduceSequential(input, from + 1, to, Root(input(from), 1))) - else { - val mid = from + (to - from)/2 - val (tL, tR) = parallel( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - - def downsweep(input: Arr[Int], a0: Root, tree: TreeRes, output: Arr[Double]): Unit = { - tree match { - case Node(left, _, right) => - parallel( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - - def downsweepSequential(input: Arr[Int], from: Int, to: Int, a0: Root, output: Arr[Double]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, Root(input(i), 1)) - output(i) = a.toDouble - i = i + 1 - } - } - } - - - def reduceSequential(input: Arr[Int], from: Int, to: Int, a0: Root): Root = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, Root(input(i), 1)) - i = i + 1 - } - a - } -} diff --git a/previous-exams/2021-midterm-solutions/m2/src/test/scala/m2/M2Suite.scala b/previous-exams/2021-midterm-solutions/m2/src/test/scala/m2/M2Suite.scala deleted file mode 100644 index a5b3a4461ea7db8a51a48de5ee0392971a61a3b6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m2/src/test/scala/m2/M2Suite.scala +++ /dev/null @@ -1,175 +0,0 @@ -package m2 - -class M2Suite extends munit.FunSuite { - - test("Rolling geometric mean result test (5pts)") { - RollingGeoMeanBasicLogicTest.basicTests() - RollingGeoMeanBasicLogicTest.normalTests() - RollingGeoMeanBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling geometric mean parallelism test (30pts)") { - RollingGeoMeanCallsToParallel.parallelismTest() - RollingGeoMeanParallel.basicTests() - RollingGeoMeanParallel.normalTests() - RollingGeoMeanParallel.largeTests() - } - - test("[TASK 2] Rolling geometric mean no `map` test (35pts)") { - RollingGeoMeanNoMap.basicTests() - RollingGeoMeanNoMap.normalTests() - RollingGeoMeanNoMap.largeTests() - } - - test("[TASK 3] Rolling geometric mean no `tail` test (30pts)") { - RollingGeoMeanNoTail.basicTests() - RollingGeoMeanNoTail.normalTests() - RollingGeoMeanNoTail.largeTests() - } - - - object RollingGeoMeanBasicLogicTest extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingGeoMeanCallsToParallel extends M2 with LibImpl with RollingGeoMeanTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingGeoMeanParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingGeoMeanNoMap extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingGeoMeanNoTail extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingGeoMeanParallel extends M2 with LibImpl with RollingGeoMeanTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingGeoMeanTest extends M2 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def asSeq(arr: Arr[Double]) = - val array = new Array[Double](arr.length) - for i <- 0 to (arr.length - 1) do - array(i) = arr(i) - array.toSeq - - def scanOp_(acc: Root, x: Root) = - Root(acc.radicand * x.radicand, acc.degree + x.degree) - - def result(ds: Seq[Int]): Arr[Double] = - Arr(ds.map(x => Root(x, 1)).scan(Root(1, 0))(scanOp_).tail.map(_.toDouble): _*) - - def check(input: Seq[Int]) = - assertEquals( - // .toString calls are a terrible kludge so that NaNs compare equal to eachother... - asSeq(rollingGeoMeanParallel(Arr(input: _*))).map(_.toString), - asSeq(result(input)).map(_.toString) - ) - - def basicTests() = { - check(Seq()) - check(Seq(1)) - check(Seq(1, 2, 3, 4)) - check(Seq(4, 4, 4, 4)) - } - - def normalTests() = { - check(Seq.tabulate(64)(identity)) - check(Seq(4, 4, 4, 4)) - check(Seq(4, 8, 6, 4)) - check(Seq(4, 3, 2, 1)) - check(Seq.tabulate(64)(identity).reverse) - check(Seq.tabulate(128)(i => 128 - 2*i).reverse) - } - - def largeTests() = { - check(Seq.tabulate(500)(identity)) - check(Seq.tabulate(512)(identity)) - check(Seq.tabulate(1_000)(identity)) - check(Seq.tabulate(10_000)(identity)) - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m20/.gitignore b/previous-exams/2021-midterm-solutions/m20/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m20/assignment.sbt b/previous-exams/2021-midterm-solutions/m20/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m20/build.sbt b/previous-exams/2021-midterm-solutions/m20/build.sbt deleted file mode 100644 index 8cd8c7a0320af71ee8405888adcaa8556c98574f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m20" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m20.M20Suite" diff --git a/previous-exams/2021-midterm-solutions/m20/grading-tests.jar b/previous-exams/2021-midterm-solutions/m20/grading-tests.jar deleted file mode 100644 index b6bb8fe06564ac4c2bec2396c5dfe7caa3b51e44..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m20/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m20/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m20/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m20/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m20/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m20/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m20/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m20/project/build.properties b/previous-exams/2021-midterm-solutions/m20/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m20/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m20/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m20/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m20/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/MultiWriterSeqCount.scala b/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/MultiWriterSeqCount.scala deleted file mode 100644 index 89df220dfc550f774c094f0f8d5de2ae829009d5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/MultiWriterSeqCount.scala +++ /dev/null @@ -1,66 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Multi-writer, multi-reader data structure containing a pair of integers. */ -class MultiWriterSeqCount extends Monitor: - /** Do not directly use this variable, use `generation`, `setGeneration` and - * `compareAndSetGeneration` instead. - */ - protected val myGeneration: AbstractAtomicVariable[Int] = new AtomicVariable(0) - protected def generation: Int = myGeneration.get - protected def setGeneration(newGeneration: Int): Unit = - myGeneration.set(newGeneration) - protected def compareAndSetGeneration(expected: Int, newValue: Int): Boolean = - myGeneration.compareAndSet(expected, newValue) - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def write(newX: Int, newY: Int): Unit = - val old = generation - if old % 2 != 0 then - write(newX, newY) - else - if !compareAndSetGeneration(old, old + 1) then - write(newX, newY) - else - setX(newX) - setY(newY) - setGeneration(old + 2) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def copy(): (Int, Int) = - val old = generation - if old % 2 != 0 then - copy() - else - val result = (x, y) - if generation != old then - copy() - else - result - -end MultiWriterSeqCount diff --git a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/SeqCount.scala b/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/SeqCount.scala deleted file mode 100644 index ff95a2c7fd783adc96044752a0781c766d93ed9c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/SeqCount.scala +++ /dev/null @@ -1,53 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Single-writer, multi-reader data structure containing a pair of integers. */ -class SeqCount extends Monitor: - /** Do not directly use this variable, use `generation` and `setGeneration` instead. */ - @volatile protected var myGeneration: Int = 0 - protected def generation: Int = myGeneration - protected def setGeneration(newGeneration: Int): Unit = - myGeneration = newGeneration - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method must only be called from one thread at a time. - */ - final def write(newX: Int, newY: Int): Unit = - setGeneration(generation + 1) - setX(newX) - setY(newY) - setGeneration(generation + 1) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def copy(): (Int, Int) = - val old = generation - if old % 2 != 0 then - copy() - else - val result = (x, y) - if generation != old then - copy() - else - result - -end SeqCount diff --git a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala b/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala deleted file mode 100644 index b96628365180b1e0c75d77f7adcdd9e56f718d3c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala +++ /dev/null @@ -1,28 +0,0 @@ -package m20.instrumentation - -import java.util.concurrent.atomic._ - -abstract class AbstractAtomicVariable[T] { - def get: T - def set(value: T): Unit - def compareAndSet(expect: T, newval: T) : Boolean -} - -class AtomicVariable[T](initial: T) extends AbstractAtomicVariable[T] { - - private val atomic = new AtomicReference[T](initial) - - override def get: T = atomic.get() - - override def set(value: T): Unit = atomic.set(value) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - val current = atomic.get - if (current == expected) { - atomic.compareAndSet(current, newValue) - } - else { - false - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/Monitor.scala b/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/Monitor.scala deleted file mode 100644 index bf844ace3980d4a1da1d59c4f80870c38c563dc6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/main/scala/m20/instrumentation/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m20.instrumentation - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: =>T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/TestSuite.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/TestSuite.scala deleted file mode 100644 index 14e707c78c31a466e107cabf565f8c1f2b8ddb75..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/TestSuite.scala +++ /dev/null @@ -1,122 +0,0 @@ -package m20 - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation._ -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -enum ThreadResult: - case WriteError(error: String) - case WriteSuccess - case Read(result: (Int, Int)) -import ThreadResult._ - -class M20Suite extends munit.FunSuite: - /** If at least one thread resulted in an error, - * return `(false, errorMessage)` otherwise return `(true, "")`. - */ - def processResults(results: List[ThreadResult]): (Boolean, String) = - val success = (true, "") - results.foldLeft(success) { - case (acc @ (false, _), _) => - // Report the first error found - acc - case (_, WriteError(error)) => - (false, error) - case (_, Read((x, y))) if x + 1 != y => - (false, s"Read ($x, $y) but expected y to be ${x + 1}") - case (_, _: Read | WriteSuccess) => - success - } - - def randomList(length: Int): List[Int] = - List.fill(length)(Random.nextInt) - - test("SeqCount: single-threaded write and copy (1 pts)") { - val sc = new SeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("SeqCount: one write thread, two copy threads (4 pts)") { - testManySchedules(3, sched => - val sc = new SchedulableSeqCount(sched) - // Invariant in this test: y == x + 1 - sc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foldLeft(WriteSuccess) { - case (res: WriteError, _) => - // Report the first error found - res - case (_, i) => - sc.write(i, i + 1) - val writtenValues = (i, i + 1) - val readBack = sc.copy() - if writtenValues != readBack then - WriteError(s"Wrote $writtenValues but read back $readBack") - else - WriteSuccess - } - - def copyThread(): ThreadResult = - Read(sc.copy()) - - val threads = List( - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - test("MultiWriterSeqCount: single-threaded write and copy (1 pts)") { - val sc = new MultiWriterSeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("MultiWriterSeqCount: two write threads, two copy threads (4 pts)") { - testManySchedules(4, sched => - val msc = new SchedulableMultiWriterSeqCount(sched) - // Invariant in this test: y == x + 1 - msc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foreach(i => msc.write(i, i + 1)) - // Unlke in the SeqCount test, we do not verify that we can read back - // the values we wrote, because the other writer thread might have - // overwritten them already. - WriteSuccess - - def copyThread(): ThreadResult = - Read(msc.copy()) - - val threads = List( - () => writeThread(), - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - import scala.concurrent.duration._ - override val munitTimeout = 200.seconds -end M20Suite - diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala deleted file mode 100644 index 0b7e94fd37926fbc2c84b4a5ca8c7113a9b9d8fc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,72 +0,0 @@ -package m20.instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Scheduler.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Scheduler.scala deleted file mode 100644 index bdc09b50f0d8ab05e89a06654034c855f98e9b3d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Scheduler.scala +++ /dev/null @@ -1,304 +0,0 @@ -package m20.instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Stats.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Stats.scala deleted file mode 100644 index e38dd2ab10b997f3e8d89fd8b9806bbb8c597e75..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package m20.instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestHelper.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestHelper.scala deleted file mode 100644 index b361ded58992134d41995527014ca62133b7e4d3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestHelper.scala +++ /dev/null @@ -1,124 +0,0 @@ -package m20.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestUtils.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestUtils.scala deleted file mode 100644 index a6a1cac480c1547251b8782042706083cbd3ce4e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/instrumentation/TestUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package m20.instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/overrides.scala b/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/overrides.scala deleted file mode 100644 index cffe5c598c82933dd3a7f7bc00d810d32c582bc6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m20/src/test/scala/m20/overrides.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec -import java.util.concurrent.atomic._ - -class SchedulableAtomicVariable[T](initial: T, scheduler: Scheduler, name: String) extends AbstractAtomicVariable[T]: - private val proxied: AtomicVariable[T] = new AtomicVariable[T](initial) - - override def get: T = scheduler.exec { - proxied.get - } (s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - proxied.set(value) - } (s"$name: set $value", None) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - scheduler.exec { - proxied.compareAndSet(expected, newValue) - } (s"$name: compareAndSet(expected = $expected, newValue = $newValue)", Some(res => s"$name: Did it set? $res") ) - } - -end SchedulableAtomicVariable - -class SchedulableSeqCount(val scheduler: Scheduler) extends SeqCount with LockFreeMonitor: - override def generation: Int = scheduler.exec { - super.generation - } ("", Some(res => s"generation is $res")) - override def setGeneration(newGeneration: Int): Unit = scheduler.exec { - super.setGeneration(newGeneration) - } ( s"setGeneration($newGeneration)", None ) - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableSeqCount - -class SchedulableMultiWriterSeqCount(val scheduler: Scheduler) extends MultiWriterSeqCount with LockFreeMonitor: - override protected val myGeneration: AbstractAtomicVariable[Int] = new SchedulableAtomicVariable(0, scheduler, "myGeneration") - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableMultiWriterSeqCount diff --git a/previous-exams/2021-midterm-solutions/m21/.gitignore b/previous-exams/2021-midterm-solutions/m21/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m21/assignment.sbt b/previous-exams/2021-midterm-solutions/m21/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m21/build.sbt b/previous-exams/2021-midterm-solutions/m21/build.sbt deleted file mode 100644 index 15c62589add717bed6163f0f77d5d607033187bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m21" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m21.M21Suite" diff --git a/previous-exams/2021-midterm-solutions/m21/grading-tests.jar b/previous-exams/2021-midterm-solutions/m21/grading-tests.jar deleted file mode 100644 index 879793e5498e751321315fff68817cea677fc435..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m21/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m21/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m21/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m21/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m21/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m21/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m21/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m21/project/build.properties b/previous-exams/2021-midterm-solutions/m21/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m21/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m21/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m21/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m21/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/MultiWriterSeqCount.scala b/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/MultiWriterSeqCount.scala deleted file mode 100644 index 73a81fb80a8cce594016ed1992be4fe246d2dab5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/MultiWriterSeqCount.scala +++ /dev/null @@ -1,66 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Multi-writer, multi-reader data structure containing a pair of integers. */ -class MultiWriterSeqCount extends Monitor: - /** Do not directly use this variable, use `generation`, `setGeneration` and - * `compareAndSetGeneration` instead. - */ - protected val myGeneration: AbstractAtomicVariable[Int] = new AtomicVariable(1) - protected def generation: Int = myGeneration.get - protected def setGeneration(newGeneration: Int): Unit = - myGeneration.set(newGeneration) - protected def compareAndSetGeneration(expected: Int, newValue: Int): Boolean = - myGeneration.compareAndSet(expected, newValue) - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def write(newX: Int, newY: Int): Unit = - val old = generation - if old % 2 != 1 then - write(newX, newY) - else - if !compareAndSetGeneration(old, old + 1) then - write(newX, newY) - else - setX(newX) - setY(newY) - setGeneration(old + 2) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def copy(): (Int, Int) = - val old = generation - if old % 2 != 1 then - copy() - else - val result = (x, y) - if generation != old then - copy() - else - result - -end MultiWriterSeqCount diff --git a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/SeqCount.scala b/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/SeqCount.scala deleted file mode 100644 index c17f45e56924d23b20cff009f8bfbf40a07fa4a0..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/SeqCount.scala +++ /dev/null @@ -1,53 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Single-writer, multi-reader data structure containing a pair of integers. */ -class SeqCount extends Monitor: - /** Do not directly use this variable, use `generation` and `setGeneration` instead. */ - @volatile protected var myGeneration: Int = 1 - protected def generation: Int = myGeneration - protected def setGeneration(newGeneration: Int): Unit = - myGeneration = newGeneration - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method must only be called from one thread at a time. - */ - final def write(newX: Int, newY: Int): Unit = - setGeneration(generation + 1) - setX(newX) - setY(newY) - setGeneration(generation + 1) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - - @tailrec - final def copy(): (Int, Int) = - val old = generation - if old % 2 != 1 then - copy() - else - val result = (x, y) - if generation != old then - copy() - else - result - -end SeqCount diff --git a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala b/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala deleted file mode 100644 index 5a5d2f4a94ad73544c265ee86d80085fcb5d48cb..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala +++ /dev/null @@ -1,28 +0,0 @@ -package m21.instrumentation - -import java.util.concurrent.atomic._ - -abstract class AbstractAtomicVariable[T] { - def get: T - def set(value: T): Unit - def compareAndSet(expect: T, newval: T) : Boolean -} - -class AtomicVariable[T](initial: T) extends AbstractAtomicVariable[T] { - - private val atomic = new AtomicReference[T](initial) - - override def get: T = atomic.get() - - override def set(value: T): Unit = atomic.set(value) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - val current = atomic.get - if (current == expected) { - atomic.compareAndSet(current, newValue) - } - else { - false - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/Monitor.scala b/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/Monitor.scala deleted file mode 100644 index 06551000717e74916191ea0ed606405390439aca..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/main/scala/m21/instrumentation/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m21.instrumentation - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: =>T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/TestSuite.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/TestSuite.scala deleted file mode 100644 index 5038092c46f6020e81887598e6e30d0f6b5d18b2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/TestSuite.scala +++ /dev/null @@ -1,122 +0,0 @@ -package m21 - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation._ -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -enum ThreadResult: - case WriteError(error: String) - case WriteSuccess - case Read(result: (Int, Int)) -import ThreadResult._ - -class M21Suite extends munit.FunSuite: - /** If at least one thread resulted in an error, - * return `(false, errorMessage)` otherwise return `(true, "")`. - */ - def processResults(results: List[ThreadResult]): (Boolean, String) = - val success = (true, "") - results.foldLeft(success) { - case (acc @ (false, _), _) => - // Report the first error found - acc - case (_, WriteError(error)) => - (false, error) - case (_, Read((x, y))) if x + 1 != y => - (false, s"Read ($x, $y) but expected y to be ${x + 1}") - case (_, _: Read | WriteSuccess) => - success - } - - def randomList(length: Int): List[Int] = - List.fill(length)(Random.nextInt) - - test("SeqCount: single-threaded write and copy (1 pts)") { - val sc = new SeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("SeqCount: one write thread, two copy threads (4 pts)") { - testManySchedules(3, sched => - val sc = new SchedulableSeqCount(sched) - // Invariant in this test: y == x + 1 - sc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foldLeft(WriteSuccess) { - case (res: WriteError, _) => - // Report the first error found - res - case (_, i) => - sc.write(i, i + 1) - val writtenValues = (i, i + 1) - val readBack = sc.copy() - if writtenValues != readBack then - WriteError(s"Wrote $writtenValues but read back $readBack") - else - WriteSuccess - } - - def copyThread(): ThreadResult = - Read(sc.copy()) - - val threads = List( - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - test("MultiWriterSeqCount: single-threaded write and copy (1 pts)") { - val sc = new MultiWriterSeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("MultiWriterSeqCount: two write threads, two copy threads (4 pts)") { - testManySchedules(4, sched => - val msc = new SchedulableMultiWriterSeqCount(sched) - // Invariant in this test: y == x + 1 - msc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foreach(i => msc.write(i, i + 1)) - // Unlke in the SeqCount test, we do not verify that we can read back - // the values we wrote, because the other writer thread might have - // overwritten them already. - WriteSuccess - - def copyThread(): ThreadResult = - Read(msc.copy()) - - val threads = List( - () => writeThread(), - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - import scala.concurrent.duration._ - override val munitTimeout = 200.seconds -end M21Suite - diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala deleted file mode 100644 index f7629e1b14693b723511bb67212fcdb16c64421c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,72 +0,0 @@ -package m21.instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Scheduler.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Scheduler.scala deleted file mode 100644 index cef9ac5155bd3c6747aea2f7c4d85e3616e84fbb..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Scheduler.scala +++ /dev/null @@ -1,304 +0,0 @@ -package m21.instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Stats.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Stats.scala deleted file mode 100644 index 6eb7239c2343a77ed7f9e8193cbacc2d57a16d61..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package m21.instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestHelper.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestHelper.scala deleted file mode 100644 index 5be75d6590a34d6e7410129e66a2f2a3b17e216c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestHelper.scala +++ /dev/null @@ -1,124 +0,0 @@ -package m21.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestUtils.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestUtils.scala deleted file mode 100644 index 5da760477971e5faad31593cd61552ec2e7b4ba6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/instrumentation/TestUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package m21.instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/overrides.scala b/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/overrides.scala deleted file mode 100644 index 92d0cec220a473d6e112d44ca7456037d08503b6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m21/src/test/scala/m21/overrides.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec -import java.util.concurrent.atomic._ - -class SchedulableAtomicVariable[T](initial: T, scheduler: Scheduler, name: String) extends AbstractAtomicVariable[T]: - private val proxied: AtomicVariable[T] = new AtomicVariable[T](initial) - - override def get: T = scheduler.exec { - proxied.get - } (s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - proxied.set(value) - } (s"$name: set $value", None) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - scheduler.exec { - proxied.compareAndSet(expected, newValue) - } (s"$name: compareAndSet(expected = $expected, newValue = $newValue)", Some(res => s"$name: Did it set? $res") ) - } - -end SchedulableAtomicVariable - -class SchedulableSeqCount(val scheduler: Scheduler) extends SeqCount with LockFreeMonitor: - override def generation: Int = scheduler.exec { - super.generation - } ("", Some(res => s"generation is $res")) - override def setGeneration(newGeneration: Int): Unit = scheduler.exec { - super.setGeneration(newGeneration) - } ( s"setGeneration($newGeneration)", None ) - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableSeqCount - -class SchedulableMultiWriterSeqCount(val scheduler: Scheduler) extends MultiWriterSeqCount with LockFreeMonitor: - override protected val myGeneration: AbstractAtomicVariable[Int] = new SchedulableAtomicVariable(1, scheduler, "myGeneration") - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableMultiWriterSeqCount diff --git a/previous-exams/2021-midterm-solutions/m3/.gitignore b/previous-exams/2021-midterm-solutions/m3/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m3/assignment.sbt b/previous-exams/2021-midterm-solutions/m3/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m3/build.sbt b/previous-exams/2021-midterm-solutions/m3/build.sbt deleted file mode 100644 index b15645acb40417c7326345ed22ac4115e6e88735..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m3" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m3.M3Suite" diff --git a/previous-exams/2021-midterm-solutions/m3/grading-tests.jar b/previous-exams/2021-midterm-solutions/m3/grading-tests.jar deleted file mode 100644 index dea8c3895d7df93482a29b4f7e0c85a5f13b7c12..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m3/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m3/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m3/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m3/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m3/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m3/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m3/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m3/project/build.properties b/previous-exams/2021-midterm-solutions/m3/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m3/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m3/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m3/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m3/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/Lib.scala b/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/Lib.scala deleted file mode 100644 index 68e89db2496199c75ec5362e9d9725f3c27facf5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/Lib.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m3 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A number representing the average of a list of integers (the "window") */ - case class AvgWin(list: List[Int]) { - def push(i: Int) = list match { - case i3 :: i2 :: i1 :: Nil => AvgWin(i :: i3 :: i2 :: Nil) - case list => AvgWin(i :: list) - } - - def pushAll(other: AvgWin) = - other.list.foldRight(this)((el, self) => self.push(el)) - - def toDouble: Double = if list.isEmpty then 0 else list.sum / list.length - } - - /** Tree result of an upsweep operation. Specialized for `AvgWin` results. */ - trait TreeRes { val res: AvgWin } - /** Leaf result of an upsweep operation. Specialized for `AvgWin` results. */ - case class Leaf(from: Int, to: Int, res: AvgWin) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `AvgWin` results. */ - case class Node(left: TreeRes, res: AvgWin, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/M3.scala b/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/M3.scala deleted file mode 100644 index 81aff199d6413684f494ca01dacd7c0f470b654d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/src/main/scala/m3/M3.scala +++ /dev/null @@ -1,75 +0,0 @@ -package m3 - - -trait M3 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling windowed mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., x_n)` the result is - * `Arr(x1, (x1+x2)/2, (x1+x2+x3)/3, (x2+x3+x4)/3, ..., (x_{n-2}, x_{n-1}, x_n)/n)` - */ - def rollingWinMeanParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - - val out: Arr[Double] = Arr.ofLength(arr.length) - val tree = upsweep(arr, 0, arr.length) - downsweep(arr, AvgWin(Nil), tree, out) - out - } - - // No need to modify this - def scanOp(acc: AvgWin, x: AvgWin) = - acc.pushAll(x) - - - def upsweep(input: Arr[Int], from: Int, to: Int): TreeRes = { - if (to - from < THRESHOLD) - Leaf(from, to, reduceSequential(input, from + 1, to, AvgWin(input(from) :: Nil))) - else { - val mid = from + (to - from)/2 - val (tL, tR) = parallel( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - - def downsweep(input: Arr[Int], a0: AvgWin, tree: TreeRes, output: Arr[Double]): Unit = { - tree match { - case Node(left, _, right) => - parallel( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - - def downsweepSequential(input: Arr[Int], from: Int, to: Int, a0: AvgWin, output: Arr[Double]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, AvgWin(input(i) :: Nil)) - output(i) = a.toDouble - i = i + 1 - } - } - } - - - def reduceSequential(input: Arr[Int], from: Int, to: Int, a0: AvgWin): AvgWin = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, AvgWin(input(i) :: Nil)) - i = i + 1 - } - a - } -} diff --git a/previous-exams/2021-midterm-solutions/m3/src/test/scala/m3/M3Suite.scala b/previous-exams/2021-midterm-solutions/m3/src/test/scala/m3/M3Suite.scala deleted file mode 100644 index 176df6a14e456a6bfa29e250d20aa94253c2360b..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m3/src/test/scala/m3/M3Suite.scala +++ /dev/null @@ -1,174 +0,0 @@ -package m3 - -class M3Suite extends munit.FunSuite { - - test("Rolling windowed average result test (5pts)") { - RollingWinMeanBasicLogicTest.basicTests() - RollingWinMeanBasicLogicTest.normalTests() - RollingWinMeanBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling windowed average parallelism test (30pts)") { - RollingWinMeanCallsToParallel.parallelismTest() - RollingWinMeanParallel.basicTests() - RollingWinMeanParallel.normalTests() - RollingWinMeanParallel.largeTests() - } - - test("[TASK 2] Rolling windowed average no `map` test (35pts)") { - RollingWinMeanNoMap.basicTests() - RollingWinMeanNoMap.normalTests() - RollingWinMeanNoMap.largeTests() - } - - test("[TASK 3] Rolling windowed average no `tail` test (30pts)") { - RollingWinMeanNoTail.basicTests() - RollingWinMeanNoTail.normalTests() - RollingWinMeanNoTail.largeTests() - } - - - object RollingWinMeanBasicLogicTest extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingWinMeanCallsToParallel extends M3 with LibImpl with RollingWinMeanTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingWinMeanParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingWinMeanNoMap extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingWinMeanNoTail extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingWinMeanParallel extends M3 with LibImpl with RollingWinMeanTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingWinMeanTest extends M3 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def asSeq(arr: Arr[Double]) = - val array = new Array[Double](arr.length) - for i <- 0 to (arr.length - 1) do - array(i) = arr(i) - array.toSeq - - def scanOp_(acc: AvgWin, x: AvgWin) = - acc.pushAll(x) - - def result(ds: Seq[Int]): Arr[Double] = - Arr(ds.map(x => AvgWin(x :: Nil)).scan(AvgWin(Nil))(scanOp_).tail.map(_.toDouble): _*) - - def check(input: Seq[Int]) = - assertEquals( - asSeq(rollingWinMeanParallel(Arr(input: _*))), - asSeq(result(input)) - ) - - def basicTests() = { - check(Seq()) - check(Seq(1)) - check(Seq(1, 2, 3, 4)) - check(Seq(4, 4, 4, 4)) - } - - def normalTests() = { - check(Seq.tabulate(64)(identity)) - check(Seq(4, 4, 4, 4)) - check(Seq(4, 8, 6, 4)) - check(Seq(4, 3, 2, 1)) - check(Seq.tabulate(64)(identity).reverse) - check(Seq.tabulate(128)(i => 128 - 2*i).reverse) - } - - def largeTests() = { - check(Seq.tabulate(500)(identity)) - check(Seq.tabulate(512)(identity)) - check(Seq.tabulate(1_000)(identity)) - check(Seq.tabulate(10_000)(identity)) - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m6/.gitignore b/previous-exams/2021-midterm-solutions/m6/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m6/assignment.sbt b/previous-exams/2021-midterm-solutions/m6/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m6/build.sbt b/previous-exams/2021-midterm-solutions/m6/build.sbt deleted file mode 100644 index 96606f6e8cb06d2e80e604e6d720bfbd3a83819c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m6" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m6.M6Suite" diff --git a/previous-exams/2021-midterm-solutions/m6/grading-tests.jar b/previous-exams/2021-midterm-solutions/m6/grading-tests.jar deleted file mode 100644 index 2127d4e28e16c94709e41b0e9a6bf7e9a5ad4b88..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m6/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m6/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m6/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m6/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m6/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m6/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m6/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m6/project/build.properties b/previous-exams/2021-midterm-solutions/m6/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m6/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m6/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m6/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m6/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/M6.scala b/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/M6.scala deleted file mode 100644 index f754c4a6b71257d94cfed13c57be81ad792c5d87..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/M6.scala +++ /dev/null @@ -1,149 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait M6 extends Lib { - - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size){ - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task1(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = head - if(current != null) { - var i_from = 0 - var i_to = 0 - copyForward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task2(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = head - if(current != null) { - var i_from = 1 - var i_to = 1 - - if(i_from >= current.cnt) { - current = current.next - if(current != null) { - i_from = 0 - } - else i_to = cnt/2 // to stop the loop - } - - copyForward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - def task3(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = last - if( current != null) { - var i_to = cnt - 2 - var i_from = current.cnt - 2 - if(i_from < 0) { - current = current.previous - if(current != null) { - i_from = current.cnt - 1 - } - else i_to = cnt/2 - 1 // to stop the loop - } - - copyBackward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]): Unit = { - - var current = last - if( current != null) { - var i_from = current.cnt - 1 - var i_to = cnt - 1 - copyBackward(data, current, i_from, i_to, cnt/2) - } - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - val t1 = task1(data) - val t2 = task2(data) - val t3 = task3(data) - - task4(data) - - t1.join() - t2.join() - t3.join() - - - data - } - - - private def copyBackward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to >= limit) { - try{ - data(i_to) = current.value(i_from) - i_to -= 2 - i_from -= 2 - if(i_from == -1) { - current = current.previous - i_from = current.cnt - 1 - } - else if(i_from == -2) { - current = current.previous - i_from = current.cnt - 2 - if(current.cnt == 1) { - current = current.previous - i_from = current.cnt - 1 - } - } - } - catch{ - case e: Exception => - } - } - - } - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to < limit) { - try { - data(i_to) = current.value(i_from) - i_to += 2 - i_from += 2 - if(i_from == current.cnt){ - current = current.next - i_from = 0 - } - else if(i_from > current.cnt) { - current = current.next - i_from = 1 - if(current.cnt == 1) { - current = current.next - i_from = 0 - } - } - } - catch{ - case e: Exception => - } - } - } - } - -} diff --git a/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/lib.scala b/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/lib.scala deleted file mode 100644 index bfb28387fa6826b708bc35f3aa47417be7064840..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/src/main/scala/m6/lib.scala +++ /dev/null @@ -1,84 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait Lib { - - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) { - var head: Node = null - var last: Node = null - var cnt: Int = 0 - var chunks: Int = 0 - - // Adds an Integer to the last node of this array combiner. If the last node is full, allocates a new node. - def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - // Combines this array combiner and another given combiner in constant O(1) complexity. - def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - - def task1(data: Array[Int]): ForkJoinTask[Unit] - def task2(data: Array[Int]): ForkJoinTask[Unit] - def task3(data: Array[Int]): ForkJoinTask[Unit] - def task4(data: Array[Int]): Unit - - def result(): Array[Int] - - } - - def task[T](body: => T): ForkJoinTask[T] - -} \ No newline at end of file diff --git a/previous-exams/2021-midterm-solutions/m6/src/test/scala/m6/M6Suite.scala b/previous-exams/2021-midterm-solutions/m6/src/test/scala/m6/M6Suite.scala deleted file mode 100644 index e04fcf064cb9f9c7262b90f94365cd4651fa49d0..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m6/src/test/scala/m6/M6Suite.scala +++ /dev/null @@ -1,422 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -class M6Suite extends AbstractM6Suite { - - // (70+) 30 / 500 points for correct implementation, don't check parallelism - test("[Correctness] fetch result - simple combiners (5pts)") { - assertCorrectnessSimple() - } - - test("[Correctness] fetch result - small combiners (5pts)") { - assertCorrectnessBasic() - } - - test("[Correctness] fetch result - small combiners after combining (10pts)") { - assertCorrectnessCombined() - } - - test("[Correctness] fetch result - large combiners (10pts)") { - assertCorrectnessLarge() - } - - def assertCorrectnessSimple() = { - simpleCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessBasic() = { - basicCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessCombined() = { - combinedCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessLarge() = { - largeCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - // (70+30+) 50 / 500 points for correct parallel implementation, don't check if it's exactly 1/4 of the array per task - private var count = 0 - private val expected = 3 - - override def task[T](body: => T): ForkJoinTask[T] = { - count += 1 - scheduler.value.schedule(body) - } - - test("[TaskCount] number of newly created tasks should be 3 (5pts)") { - assertTaskCountSimple() - } - - test("[TaskCount] fetch result and check parallel - simple combiners (5pts)") { - assertTaskCountSimple() - assertCorrectnessSimple() - } - - test("[TaskCount] fetch result and check parallel - small combiners (10pts)") { - assertTaskCountSimple() - assertCorrectnessBasic() - } - - test("[TaskCount] fetch result and check parallel - small combiners after combining (15pts)") { - assertTaskCountSimple() - assertCorrectnessCombined() - } - - test("[TaskCount] fetch result and check parallel - large combiners (15pts)") { - assertTaskCountSimple() - assertCorrectnessLarge() - } - - def assertTaskCountSimple(): Unit = { - simpleCombiners.foreach(elem => assertTaskCount(elem._1, elem._2)) - } - - def assertTaskCount(combiner: DLLCombinerTest, array: Array[Int]): Unit = { - try { - count = 0 - build(combiner, array) - combiner.result() - assertEquals(count, expected, { - s"ERROR: Expected $expected instead of $count calls to `task(...)`" - }) - } finally { - count = 0 - } - } - - //(70+30+50+) 200 / 500 points for correct parallel implementation, exactly 1/4 of the array per task - test("[TaskFairness] each task should compute 1/4 of the result (50pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - simple combiners (20pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - assertCorrectnessSimple() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners (30pts)") { - assertTaskFairness(basicCombiners.unzip._1) - assertCorrectnessBasic() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners after combining (50pts)") { - assertTaskFairness(combinedCombiners.unzip._1) - assertCorrectnessCombined() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - large combiners (50pts)") { - assertTaskFairness(largeCombiners.unzip._1) - assertCorrectnessLarge() - } - - def assertTaskFairness(combiners: List[DLLCombinerTest]): Unit = { - def assertNewTaskFairness(combiner: DLLCombinerTest, task: ForkJoinTask[Unit], data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - task.join - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - def assertMainTaskFairness(combiner: DLLCombinerTest, task: Unit, data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - combiners.foreach { elem => - var data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task1(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task2(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task3(data), data) - - data = Array.fill(elem.cnt)(0) - assertMainTaskFairness(elem, elem.task4(data), data) - } - } - - //(70+30+50+200+) 150 / 500 points for correct parallel implementation, exactly 1/4 of the array per task, exactly the specified quarter - - test("[TaskPrecision] each task should compute specified 1/4 of the result - simple combiners (20pts)") { - assertTaskPrecision(simpleCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners (30pts)") { - assertTaskPrecision(basicCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners after combining (50pts)") { - assertTaskPrecision(combinedCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - large combiners (50pts)") { - assertTaskPrecision(largeCombiners) - } - - def assertTaskPrecision(combiners: List[(DLLCombinerTest, Array[Int])]): Unit = { - combiners.foreach { elem => - var data = Array.fill(elem._1.cnt)(0) - var ref = Array.fill(elem._1.cnt)(0) - val task1 = elem._1.task1(data) - task1.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 0) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task2 = elem._1.task2(data) - task2.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 1) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task3 = elem._1.task3(data) - task3.join - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 == elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task4 = elem._1.task4(data) - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 != elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - } - } - - test("[Public] fetch simple result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1, 2, 3, 8) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result after simple combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - - val combiner2 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 8 - - val combiner3 = DLLCombinerTest(2) - combiner2 += 1 - combiner2 += 9 - - val combiner4 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 2 - - val result = combiner1.combine(combiner2).combine(combiner3).combine(combiner4).result() - val array = Array(7, 2, 3, 8, 1, 9, 3, 2) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result - empty combiner (20pts)") { - val combiner1 = DLLCombinerTest(2) - val result = combiner1.result() - assertEquals(result.size, 0) - } - - test("[Public] fetch result - full single element combiner (15pts)") { - val combiner1 = DLLCombinerTest(3) - combiner1 += 4 - combiner1 += 2 - combiner1 += 6 - - val result = combiner1.result() - val array = Array(4, 2, 6) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - -} - - -trait AbstractM6Suite extends munit.FunSuite with LibImpl { - - def simpleCombiners = buildSimpleCombiners() - def basicCombiners = buildBasicCombiners() - def combinedCombiners = buildCombinedCombiners() - def largeCombiners = buildLargeCombiners() - - def buildSimpleCombiners() = { - val simpleCombiners = List( - (DLLCombinerTest(4), Array(4, 2, 6, 1, 5, 4, 3, 5, 6, 3, 4, 5, 6, 3, 4, 5)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2)), - (DLLCombinerTest(4), Array.fill(16)(5)) - ) - simpleCombiners.foreach(elem => build(elem._1, elem._2)) - simpleCombiners - } - - def buildBasicCombiners() = { - val basicCombiners = List( - (DLLCombinerTest(2), Array(4, 2, 6)), - (DLLCombinerTest(5), Array(4, 2, 6)), - (DLLCombinerTest(3), Array(4, 2, 6, 1, 7, 2, 4)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 11, 12, 13, 14, 15, 16, 17, 22)), - (DLLCombinerTest(3), Array.fill(16)(7)), - (DLLCombinerTest(3), Array.fill(19)(7)), - (DLLCombinerTest(3), Array.fill(5)(7)), - (DLLCombinerTest(3), Array.fill(6)(7)) - ) - basicCombiners.foreach(elem => build(elem._1, elem._2)) - basicCombiners - } - - def buildCombinedCombiners() = { - var combinedCombiners = List[(DLLCombinerTest, Array[Int])]() - Range(1, 10).foreach { chunk_size => - val array = basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foldLeft(Array[Int]()) { (acc, i) => acc ++ i._2 } - val combiner = DLLCombinerTest(chunk_size) - basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foreach(elem => combiner.combine(elem._1)) - - combinedCombiners = combinedCombiners :+ (combiner, array) - } - combinedCombiners - } - - def buildLargeCombiners() = { - val largeCombiners = List( - (DLLCombinerTest(21), Array.fill(1321)(4) ++ Array.fill(1322)(7)), - (DLLCombinerTest(18), Array.fill(1341)(2) ++ Array.fill(1122)(5)), - (DLLCombinerTest(3), Array.fill(1321)(4) ++ Array.fill(1322)(7) ++ Array.fill(321)(4) ++ Array.fill(322)(7)), - (DLLCombinerTest(12), Array.fill(992321)(4) ++ Array.fill(99322)(7)), - (DLLCombinerTest(4), Array.fill(953211)(4) ++ Array.fill(999322)(1)) - ) - largeCombiners.foreach(elem => build(elem._1, elem._2)) - largeCombiners - } - - def build(combiner: DLLCombinerTest, array: Array[Int]): DLLCombinerTest = { - array.foreach(elem => combiner += elem) - combiner - } - - def compare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - val result = combiner.result() - Range(0,array.size).forall(i => array(i) == result(i)) - } - - def buildAndCompare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - array.foreach(elem => combiner += elem) - val result = combiner.result() - - Range(0,array.size).forall(i => array(i) == result(i)) - } - -} - -trait LibImpl extends M6 { - - val forkJoinPool = new ForkJoinPool - - abstract class TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] - } - - class DefaultTaskScheduler extends TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] = { - val t = new RecursiveTask[T] { - def compute = body - } - Thread.currentThread match { - case wt: ForkJoinWorkerThread => - t.fork() - case _ => - forkJoinPool.execute(t) - } - t - } - } - - val scheduler = - new DynamicVariable[TaskScheduler](new DefaultTaskScheduler) - - def task[T](body: => T): ForkJoinTask[T] = { - scheduler.value.schedule(body) - } - - class DLLCombinerTest(chunk_size: Int = 3) extends DLLCombinerImplementation(chunk_size) { - - override def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - override def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - } -} diff --git a/previous-exams/2021-midterm-solutions/m7/.gitignore b/previous-exams/2021-midterm-solutions/m7/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm-solutions/m7/assignment.sbt b/previous-exams/2021-midterm-solutions/m7/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm-solutions/m7/build.sbt b/previous-exams/2021-midterm-solutions/m7/build.sbt deleted file mode 100644 index 25a0926a0020518f0905ffb468b8daccfb2489c4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m7" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m7.M7Suite" diff --git a/previous-exams/2021-midterm-solutions/m7/grading-tests.jar b/previous-exams/2021-midterm-solutions/m7/grading-tests.jar deleted file mode 100644 index 4536552028df3dbab3c2d6fd1d7ae9f4f1322f75..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-solutions/m7/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm-solutions/m7/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm-solutions/m7/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm-solutions/m7/project/MOOCSettings.scala b/previous-exams/2021-midterm-solutions/m7/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm-solutions/m7/project/StudentTasks.scala b/previous-exams/2021-midterm-solutions/m7/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm-solutions/m7/project/build.properties b/previous-exams/2021-midterm-solutions/m7/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm-solutions/m7/project/buildSettings.sbt b/previous-exams/2021-midterm-solutions/m7/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm-solutions/m7/project/plugins.sbt b/previous-exams/2021-midterm-solutions/m7/project/plugins.sbt deleted file mode 100644 index 021c01988a1b773f2fa8ad84758b9bff1225dcf8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/M7.scala b/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/M7.scala deleted file mode 100644 index d941f26111e8732e80c8208ec9251a5b37828b79..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/M7.scala +++ /dev/null @@ -1,149 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait M7 extends Lib { - - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size){ - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task1(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = head - if(current != null) { - var i_from = 1 - var i_to = 1 - - if(i_from >= current.cnt) { - current = current.next - if(current != null) { - i_from = 0 - } - else i_to = cnt/2 // to stop the loop - } - - copyForward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task2(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = head - if(current != null) { - var i_from = 0 - var i_to = 0 - copyForward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - def task3(data: Array[Int]): ForkJoinTask[Unit] = task { - - var current = last - if( current != null) { - var i_from = current.cnt - 1 - var i_to = cnt - 1 - copyBackward(data, current, i_from, i_to, cnt/2) - } - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]): Unit = { - - var current = last - if( current != null) { - var i_to = cnt - 2 - var i_from = current.cnt - 2 - if(i_from < 0) { - current = current.previous - if(current != null) { - i_from = current.cnt - 1 - } - else i_to = cnt/2 - 1 // to stop the loop - } - - copyBackward(data, current, i_from, i_to, cnt/2) - } - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - val t1 = task1(data) - val t2 = task2(data) - val t3 = task3(data) - - task4(data) - - t1.join() - t2.join() - t3.join() - - - data - } - - - private def copyBackward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to >= limit) { - try{ - data(i_to) = current.value(i_from) - i_to -= 2 - i_from -= 2 - if(i_from == -1) { - current = current.previous - i_from = current.cnt - 1 - } - else if(i_from == -2) { - current = current.previous - i_from = current.cnt - 2 - if(current.cnt == 1) { - current = current.previous - i_from = current.cnt - 1 - } - } - } - catch{ - case e: Exception => - } - } - - } - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to < limit) { - try { - data(i_to) = current.value(i_from) - i_to += 2 - i_from += 2 - if(i_from == current.cnt){ - current = current.next - i_from = 0 - } - else if(i_from > current.cnt) { - current = current.next - i_from = 1 - if(current.cnt == 1) { - current = current.next - i_from = 0 - } - } - } - catch{ - case e: Exception => - } - } - } - } - -} diff --git a/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/lib.scala b/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/lib.scala deleted file mode 100644 index 20eda60c5fe1bae1271615650af917ff08929690..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/src/main/scala/m7/lib.scala +++ /dev/null @@ -1,84 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait Lib { - - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) { - var head: Node = null - var last: Node = null - var cnt: Int = 0 - var chunks: Int = 0 - - // Adds an Integer to the last node of this array combiner. If the last node is full, allocates a new node. - def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - // Combines this array combiner and another given combiner in constant O(1) complexity. - def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - - def task1(data: Array[Int]): ForkJoinTask[Unit] - def task2(data: Array[Int]): ForkJoinTask[Unit] - def task3(data: Array[Int]): ForkJoinTask[Unit] - def task4(data: Array[Int]): Unit - - def result(): Array[Int] - - } - - def task[T](body: => T): ForkJoinTask[T] - -} \ No newline at end of file diff --git a/previous-exams/2021-midterm-solutions/m7/src/test/scala/m7/M7Suite.scala b/previous-exams/2021-midterm-solutions/m7/src/test/scala/m7/M7Suite.scala deleted file mode 100644 index 8e1c344eacca6b10c5646a7318fb1c0c19252bc5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solutions/m7/src/test/scala/m7/M7Suite.scala +++ /dev/null @@ -1,422 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -class M7Suite extends AbstractM7Suite { - - // (70+) 30 / 500 points for correct implementation, don't check parallelism - test("[Correctness] fetch result - simple combiners (5pts)") { - assertCorrectnessSimple() - } - - test("[Correctness] fetch result - small combiners (5pts)") { - assertCorrectnessBasic() - } - - test("[Correctness] fetch result - small combiners after combining (10pts)") { - assertCorrectnessCombined() - } - - test("[Correctness] fetch result - large combiners (10pts)") { - assertCorrectnessLarge() - } - - def assertCorrectnessSimple() = { - simpleCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessBasic() = { - basicCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessCombined() = { - combinedCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessLarge() = { - largeCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - // (70+30+) 50 / 500 points for correct parallel implementation, don't check if it's exactly 1/4 of the array per task - private var count = 0 - private val expected = 3 - - override def task[T](body: => T): ForkJoinTask[T] = { - count += 1 - scheduler.value.schedule(body) - } - - test("[TaskCount] number of newly created tasks should be 3 (5pts)") { - assertTaskCountSimple() - } - - test("[TaskCount] fetch result and check parallel - simple combiners (5pts)") { - assertTaskCountSimple() - assertCorrectnessSimple() - } - - test("[TaskCount] fetch result and check parallel - small combiners (10pts)") { - assertTaskCountSimple() - assertCorrectnessBasic() - } - - test("[TaskCount] fetch result and check parallel - small combiners after combining (15pts)") { - assertTaskCountSimple() - assertCorrectnessCombined() - } - - test("[TaskCount] fetch result and check parallel - large combiners (15pts)") { - assertTaskCountSimple() - assertCorrectnessLarge() - } - - def assertTaskCountSimple(): Unit = { - simpleCombiners.foreach(elem => assertTaskCount(elem._1, elem._2)) - } - - def assertTaskCount(combiner: DLLCombinerTest, array: Array[Int]): Unit = { - try { - count = 0 - build(combiner, array) - combiner.result() - assertEquals(count, expected, { - s"ERROR: Expected $expected instead of $count calls to `task(...)`" - }) - } finally { - count = 0 - } - } - - //(70+30+50+) 200 / 500 points for correct parallel implementation, exactly 1/4 of the array per task - test("[TaskFairness] each task should compute 1/4 of the result (50pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - simple combiners (20pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - assertCorrectnessSimple() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners (30pts)") { - assertTaskFairness(basicCombiners.unzip._1) - assertCorrectnessBasic() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners after combining (50pts)") { - assertTaskFairness(combinedCombiners.unzip._1) - assertCorrectnessCombined() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - large combiners (50pts)") { - assertTaskFairness(largeCombiners.unzip._1) - assertCorrectnessLarge() - } - - def assertTaskFairness(combiners: List[DLLCombinerTest]): Unit = { - def assertNewTaskFairness(combiner: DLLCombinerTest, task: ForkJoinTask[Unit], data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - task.join - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - def assertMainTaskFairness(combiner: DLLCombinerTest, task: Unit, data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - combiners.foreach { elem => - var data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task1(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task2(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task3(data), data) - - data = Array.fill(elem.cnt)(0) - assertMainTaskFairness(elem, elem.task4(data), data) - } - } - - //(70+30+50+200+) 150 / 500 points for correct parallel implementation, exactly 1/4 of the array per task, exactly the specified quarter - - test("[TaskPrecision] each task should compute specified 1/4 of the result - simple combiners (20pts)") { - assertTaskPrecision(simpleCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners (30pts)") { - assertTaskPrecision(basicCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners after combining (50pts)") { - assertTaskPrecision(combinedCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - large combiners (50pts)") { - assertTaskPrecision(largeCombiners) - } - - def assertTaskPrecision(combiners: List[(DLLCombinerTest, Array[Int])]): Unit = { - combiners.foreach { elem => - var data = Array.fill(elem._1.cnt)(0) - var ref = Array.fill(elem._1.cnt)(0) - val task1 = elem._1.task1(data) - task1.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 1) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task2 = elem._1.task2(data) - task2.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 0) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task3 = elem._1.task3(data) - task3.join - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 != elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task4 = elem._1.task4(data) - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 == elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - } - } - - test("[Public] fetch simple result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1, 2, 3, 8) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result after simple combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - - val combiner2 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 8 - - val combiner3 = DLLCombinerTest(2) - combiner2 += 1 - combiner2 += 9 - - val combiner4 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 2 - - val result = combiner1.combine(combiner2).combine(combiner3).combine(combiner4).result() - val array = Array(7, 2, 3, 8, 1, 9, 3, 2) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result - empty combiner (20pts)") { - val combiner1 = DLLCombinerTest(2) - val result = combiner1.result() - assertEquals(result.size, 0) - } - - test("[Public] fetch result - full single element combiner (15pts)") { - val combiner1 = DLLCombinerTest(3) - combiner1 += 4 - combiner1 += 2 - combiner1 += 6 - - val result = combiner1.result() - val array = Array(4, 2, 6) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - -} - - -trait AbstractM7Suite extends munit.FunSuite with LibImpl { - - def simpleCombiners = buildSimpleCombiners() - def basicCombiners = buildBasicCombiners() - def combinedCombiners = buildCombinedCombiners() - def largeCombiners = buildLargeCombiners() - - def buildSimpleCombiners() = { - val simpleCombiners = List( - (DLLCombinerTest(4), Array(4, 2, 6, 1, 5, 4, 3, 5, 6, 3, 4, 5, 6, 3, 4, 5)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2)), - (DLLCombinerTest(4), Array.fill(16)(5)) - ) - simpleCombiners.foreach(elem => build(elem._1, elem._2)) - simpleCombiners - } - - def buildBasicCombiners() = { - val basicCombiners = List( - (DLLCombinerTest(2), Array(4, 2, 6)), - (DLLCombinerTest(5), Array(4, 2, 6)), - (DLLCombinerTest(3), Array(4, 2, 6, 1, 7, 2, 4)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 11, 12, 13, 14, 15, 16, 17, 22)), - (DLLCombinerTest(3), Array.fill(16)(7)), - (DLLCombinerTest(3), Array.fill(19)(7)), - (DLLCombinerTest(3), Array.fill(5)(7)), - (DLLCombinerTest(3), Array.fill(6)(7)) - ) - basicCombiners.foreach(elem => build(elem._1, elem._2)) - basicCombiners - } - - def buildCombinedCombiners() = { - var combinedCombiners = List[(DLLCombinerTest, Array[Int])]() - Range(1, 10).foreach { chunk_size => - val array = basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foldLeft(Array[Int]()) { (acc, i) => acc ++ i._2 } - val combiner = DLLCombinerTest(chunk_size) - basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foreach(elem => combiner.combine(elem._1)) - - combinedCombiners = combinedCombiners :+ (combiner, array) - } - combinedCombiners - } - - def buildLargeCombiners() = { - val largeCombiners = List( - (DLLCombinerTest(21), Array.fill(1321)(4) ++ Array.fill(1322)(7)), - (DLLCombinerTest(18), Array.fill(1341)(2) ++ Array.fill(1122)(5)), - (DLLCombinerTest(3), Array.fill(1321)(4) ++ Array.fill(1322)(7) ++ Array.fill(321)(4) ++ Array.fill(322)(7)), - (DLLCombinerTest(12), Array.fill(992321)(4) ++ Array.fill(99322)(7)), - (DLLCombinerTest(4), Array.fill(953211)(4) ++ Array.fill(999322)(1)) - ) - largeCombiners.foreach(elem => build(elem._1, elem._2)) - largeCombiners - } - - def build(combiner: DLLCombinerTest, array: Array[Int]): DLLCombinerTest = { - array.foreach(elem => combiner += elem) - combiner - } - - def compare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - val result = combiner.result() - Range(0,array.size).forall(i => array(i) == result(i)) - } - - def buildAndCompare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - array.foreach(elem => combiner += elem) - val result = combiner.result() - - Range(0,array.size).forall(i => array(i) == result(i)) - } - -} - -trait LibImpl extends M7 { - - val forkJoinPool = new ForkJoinPool - - abstract class TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] - } - - class DefaultTaskScheduler extends TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] = { - val t = new RecursiveTask[T] { - def compute = body - } - Thread.currentThread match { - case wt: ForkJoinWorkerThread => - t.fork() - case _ => - forkJoinPool.execute(t) - } - t - } - } - - val scheduler = - new DynamicVariable[TaskScheduler](new DefaultTaskScheduler) - - def task[T](body: => T): ForkJoinTask[T] = { - scheduler.value.schedule(body) - } - - class DLLCombinerTest(chunk_size: Int = 3) extends DLLCombinerImplementation(chunk_size) { - - override def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - override def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - } -} diff --git a/previous-exams/2021-midterm/m1.md b/previous-exams/2021-midterm/m1.md deleted file mode 100644 index 49f825688c2c36e8dd2daee4c7b27311635377f4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1.md +++ /dev/null @@ -1,55 +0,0 @@ -## 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.** - -## Exercise - -Given the following sequential implementation of a function that computes the sequence of rolling averages, your task will be to complete and optimize a parallel version of this code. - -```scala -/** Compute the rolling average of array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(x1 / 1, (x1 + x2) / 2, (x1 + x2 + x3) / 3, ..., (x1 + x2 + x3 + ... + xn) / n)` - */ -def rollingAveragesSequential(arr: Array[Int]): Array[Double] = - // Transform all numbers to fractions with denominator 1 - val arr1 = arr.map(x => Frac(x, 1)) - // Compute the rolling average keeping the sum of all elements in the numerator and the count of elements in the denominator. - val arr2 = arr1.scan(Frac(0, 0))((acc, x) => Frac(acc.numerator + x.numerator, acc.denominator + x.denominator)) - // Transform fractions to Doubles - arr2.map(frac => frac.toDouble) - // Drop the extra initial element that was added by the scan - arr3.tail -``` - - This implementation has some issues: - - It does not use parallelism - - Creates two intermediate arrays by calling `map` - - Creates an extra intermediate arrays by calling `tail` - - Scan returns an extra element we do not need - - We want to parallelize and avoid the creation of the extra arrays. - As we are calling a `scan` the natural operations we need are `upsweep` and `downsweep`. - It is possible specialize those operations for our problem by letting those operations do the mapping. - It is also possible to change those operations to not generate the first element. - -We give you a version of `rollingAveragesSequential` that partially implements the parallelization using `upsweep` and `downsweep`. - - Your tasks in the exercise will be to: - - TASK 1: Implement the parallelization of `upsweep` and `downsweep` - - TASK 2: Remove the calls to the `map` - - TASK 3: Remove the call to `tail` - - You can get partial points for solving part of the tasks. - The order of the tasks is a suggestion, you may do them in any order if that is simpler for you. - -Look at the `Lib` trait to find the definitions of functions and classes you can use (or already used). -In this question we use a `Arr` array class instead of the normal `Array`. You may assume that this class has the same performance characteristics as the normal array. `Arr` provides only a limited set of operations. diff --git a/previous-exams/2021-midterm/m1/.gitignore b/previous-exams/2021-midterm/m1/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m1/assignment.sbt b/previous-exams/2021-midterm/m1/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m1/build.sbt b/previous-exams/2021-midterm/m1/build.sbt deleted file mode 100644 index e4766880cca56983c63e60a86fd6e83af3750053..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m1" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m1.M1Suite" diff --git a/previous-exams/2021-midterm/m1/grading-tests.jar b/previous-exams/2021-midterm/m1/grading-tests.jar deleted file mode 100644 index e01bbb513ff0587ef7115a1037909157c65ef0fb..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m1/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m1/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m1/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m1/project/MOOCSettings.scala b/previous-exams/2021-midterm/m1/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m1/project/StudentTasks.scala b/previous-exams/2021-midterm/m1/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m1/project/build.properties b/previous-exams/2021-midterm/m1/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m1/project/buildSettings.sbt b/previous-exams/2021-midterm/m1/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m1/project/plugins.sbt b/previous-exams/2021-midterm/m1/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m1/src/main/scala/m1/Lib.scala b/previous-exams/2021-midterm/m1/src/main/scala/m1/Lib.scala deleted file mode 100644 index 37ce78015dfcc3dd679e238ab5bad98903b7e03c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/src/main/scala/m1/Lib.scala +++ /dev/null @@ -1,60 +0,0 @@ -package m1 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A fractional number representing `numerator/denominator` */ - case class Frac(numerator: Int, denominator: Int) { - def toDouble: Double = numerator.toDouble / denominator - } - - /** Tree result of an upsweep operation. Specialized for `Frac` results. */ - trait TreeRes { val res: Frac } - /** Leaf result of an upsweep operation. Specialized for `Frac` results. */ - case class Leaf(from: Int, to: Int, res: Frac) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `Frac` results. */ - case class Node(left: TreeRes, res: Frac, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm/m1/src/main/scala/m1/M1.scala b/previous-exams/2021-midterm/m1/src/main/scala/m1/M1.scala deleted file mode 100644 index 8eaea55ff391cd121b054a8fe3fc9a22e3e4e089..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/src/main/scala/m1/M1.scala +++ /dev/null @@ -1,90 +0,0 @@ -package m1 - - -trait M1 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling average of array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(x1 / 1, (x1 + x2) / 2, (x1 + x2 + x3) / 3, ..., (x1 + x2 + x3 + ... + xn) / n)` - */ - def rollingAveragesParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - // TASK 1: Add missing parallelization in `upsweep` and `downsweep`. - // You should use the `parallel` method. - // You should use the sequential version if the number of elements is lower than THRESHOLD. - // TASK 2a: Pass `arr` to `upsweep` and `downsweep` instead of `tmp`. - // You will need to change some signatures and update the code appropriately. - // Remove the definition of `tmp` - // TASK 2b: Change the type of the array `out` from `Frac` to `Double` - // You will need to change some signatures and update the code appropriately. - // Remove the call `.map(frac => frac.toDouble)`. - // TASK 3: Remove the call to `.tail`. - // Update the update the code appropriately. - - val tmp: Arr[Frac] = arr.map(x => Frac(x, 1)) - val out: Arr[Frac] = Arr.ofLength(arr.length + 1) - val tree = upsweep(tmp, 0, arr.length) - downsweep(tmp, Frac(0, 0), tree, out) - out(0) = Frac(0, 0) - out.map(frac => frac.toDouble).tail - - // IDEAL SOLUTION - // val out = Arr.ofLength(arr.length) - // val tree = upsweep(arr, 0, arr.length) - // downsweep(arr, Frac(0, 0), tree, out) - // out - } - - def scanOp(acc: Frac, x: Frac) = // No need to modify this method - Frac(acc.numerator + x.numerator, acc.denominator + x.denominator) - - def upsweep(input: Arr[Frac], from: Int, to: Int): TreeRes = { - if (to - from < 2) - Leaf(from, to, reduceSequential(input, from + 1, to, input(from))) - else { - val mid = from + (to - from) / 2 - val (tL, tR) = ( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - def downsweep(input: Arr[Frac], a0: Frac, tree: TreeRes, output: Arr[Frac]): Unit = { - tree match { - case Node(left, _, right) => - ( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - def downsweepSequential(input: Arr[Frac], from: Int, to: Int, a0: Frac, output: Arr[Frac]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - output(i) = a - } - } - } - - def reduceSequential(input: Arr[Frac], from: Int, to: Int, a0: Frac): Frac = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - } - a - } - -} diff --git a/previous-exams/2021-midterm/m1/src/test/scala/m1/M1Suite.scala b/previous-exams/2021-midterm/m1/src/test/scala/m1/M1Suite.scala deleted file mode 100644 index ab1b8652a90c04eddcf5767bc413126be1152f6e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m1/src/test/scala/m1/M1Suite.scala +++ /dev/null @@ -1,156 +0,0 @@ -package m1 - -class M1Suite extends munit.FunSuite { - - test("Rolling average result test (5pts)") { - RollingAveragesBasicLogicTest.basicTests() - RollingAveragesBasicLogicTest.normalTests() - RollingAveragesBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling average parallelism test (30pts)") { - RollingAveragesCallsToParallel.parallelismTest() - RollingAveragesParallel.basicTests() - RollingAveragesParallel.normalTests() - RollingAveragesParallel.largeTests() - } - - test("[TASK 2] Rolling average no `map` test (35pts)") { - RollingAveragesNoMap.basicTests() - RollingAveragesNoMap.normalTests() - RollingAveragesNoMap.largeTests() - } - - test("[TASK 3] Rolling average no `tail` test (30pts)") { - RollingAveragesNoTail.basicTests() - RollingAveragesNoTail.normalTests() - RollingAveragesNoTail.largeTests() - } - - - object RollingAveragesBasicLogicTest extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingAveragesCallsToParallel extends M1 with LibImpl with RollingAveragesTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingAveragesParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingAveragesNoMap extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingAveragesNoTail extends M1 with LibImpl with RollingAveragesTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingAveragesParallel extends M1 with LibImpl with RollingAveragesTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingAveragesTest extends M1 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def basicTests() = { - assertEquals(rollingAveragesParallel(Arr()), Arr[Double]()) - assertEquals(rollingAveragesParallel(Arr(1)), Arr[Double](1)) - assertEquals(rollingAveragesParallel(Arr(1, 2, 3, 4)), Arr(1, 1.5, 2, 2.5)) - assertEquals(rollingAveragesParallel(Arr(4, 4, 4, 4)), Arr[Double](4, 4, 4, 4)) - } - - def normalTests() = { - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(64)(identity): _*)), Arr(Array.tabulate(64)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(4, 4, 4, 4)), Arr[Double](4, 4, 4, 4)) - assertEquals(rollingAveragesParallel(Arr(4, 8, 6, 4)), Arr[Double](4, 6, 6, 5.5)) - assertEquals(rollingAveragesParallel(Arr(4, 3, 2, 1)), Arr(4, 3.5, 3, 2.5)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(64)(identity).reverse: _*)), Arr(Array.tabulate(64)(i => 63 - i.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(128)(i => 128 - 2*i).reverse: _*)), Arr(Array.tabulate(128)(i => -126d + i): _*)) - } - - def largeTests() = { - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(500)(identity): _*)), Arr(Array.tabulate(500)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(512)(identity): _*)), Arr(Array.tabulate(512)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(1_000)(identity): _*)), Arr(Array.tabulate(1_000)(_.toDouble / 2): _*)) - assertEquals(rollingAveragesParallel(Arr(Array.tabulate(10_000)(identity): _*)), Arr(Array.tabulate(10_000)(_.toDouble / 2): _*)) - } - } -} \ No newline at end of file diff --git a/previous-exams/2021-midterm/m14.md b/previous-exams/2021-midterm/m14.md deleted file mode 100644 index 7b0deeb4e9c7712f21d55b7a861a81927c7afa0e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14.md +++ /dev/null @@ -1,36 +0,0 @@ -## 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.** - -## Exercise - -In this question, you will implement a simple thread pool executor. -Thread pool executors provide a way to execute tasks in parallel using one of several pooled threads. -Using a pool of threads provides improved performance compared to creating a new thread for every operation since threads in the pool are reused throughout the executor's lifetime. - -Thread pool executors are one of the core primitive used to implement parallel programs. For example, they are the underlying mechanism used in the implementation of `Future`-s. - -Your task is to complete the implementation of the `ThreadPoolExecutor` class. This class' constructor takes the number of threads of the pool as argument and exposes two life-cycle methods (`start` and `shutdown`), and an `execute` method to run tasks on the thread pool. The `execute` method takes as argument `Unit => Unit` functions. These functions can be constructed anonymously using the following syntax: `val func = (x: Unit) => println("hello")`. Furthermore, given a `func` function of type `Unit => Unit`, one can invoke that function using `func(())`. -For the purpose of this exercise, you can assume that the tasks submitted to the thread pool via the `execute` method do not throw exceptions. - -The thread pool implementation uses two additional classes: -- `BlockingQueue`, used by the `ThreadPoolExecutor` to store pending tasks, -- `Worker`-s, which each run in a separate thread, consume tasks from the queue and execute those tasks. - -The `BlockingQueue` implements two methods: -- `put` to insert an element in the queue -- `take` to retrieve and remove an element from the queue, in a last in first out order. - -The `put` operation always succeeds and is non-blocking (the queue is unbounded). -The `take` operation is a potentially blocking operation that waits for new elements when called on an empty queue. - -Given that `Worker`-s run on separate threads, the `take` operation must be thread-safe. Furthermore, since the thread pool executor could also be used from multiple threads, the `put` operation should also be thread-safe. -Your implementation should use a single lock to achieve this thread safety, specifically using the `[wait](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait())`/`[notify](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify())`/`[notifyAll](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notifyAll())`/`synchronized` primitives. -Remember that `wait`, `notify` and `notifyAll` should only be invoked inside a synchronized block. diff --git a/previous-exams/2021-midterm/m14/.gitignore b/previous-exams/2021-midterm/m14/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m14/assignment.sbt b/previous-exams/2021-midterm/m14/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m14/build.sbt b/previous-exams/2021-midterm/m14/build.sbt deleted file mode 100644 index aeee575ac20b4770fe264f7327098c1da3387794..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m14" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m14.M14Suite" diff --git a/previous-exams/2021-midterm/m14/grading-tests.jar b/previous-exams/2021-midterm/m14/grading-tests.jar deleted file mode 100644 index 9c8d6fdaac52512ffcac6882f5650c7673caa5f4..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m14/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m14/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m14/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m14/project/MOOCSettings.scala b/previous-exams/2021-midterm/m14/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m14/project/StudentTasks.scala b/previous-exams/2021-midterm/m14/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m14/project/build.properties b/previous-exams/2021-midterm/m14/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m14/project/buildSettings.sbt b/previous-exams/2021-midterm/m14/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m14/project/plugins.sbt b/previous-exams/2021-midterm/m14/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractBlockingQueue.scala b/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractBlockingQueue.scala deleted file mode 100644 index a91a39c7ce364151f5c2aa9968de43aecc1ef984..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractBlockingQueue.scala +++ /dev/null @@ -1,14 +0,0 @@ -package m14 - -abstract class AbstractBlockingQueue[T] extends Monitor { - private var underlying: List[T] = Nil - - def getUnderlying(): List[T] = - underlying - - def setUnderlying(newValue: List[T]): Unit = - underlying = newValue - - def put(elem: T): Unit - def take(): T -} diff --git a/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala b/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala deleted file mode 100644 index 670294c04eaa9376c25984061168a2c0ad275669..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/main/scala/m14/AbstractThreadPoolExecutor.scala +++ /dev/null @@ -1,7 +0,0 @@ -package m14 - -abstract class AbstractThreadPoolExecutor { - def execute(task: Unit => Unit): Unit - def start(): Unit - def shutdown(): Unit -} diff --git a/previous-exams/2021-midterm/m14/src/main/scala/m14/M14.scala b/previous-exams/2021-midterm/m14/src/main/scala/m14/M14.scala deleted file mode 100644 index 18229ebdeed559f400045c0b20595394f0ac88f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/main/scala/m14/M14.scala +++ /dev/null @@ -1,62 +0,0 @@ -package m14 - -object M14 { - /** A thread pool that executes submitted task using one of several threads */ - class ThreadPoolExecutor(taskQueue: BlockingQueue[Unit => Unit], poolSize: Int) - extends AbstractThreadPoolExecutor { - - private class Worker extends Thread { - override def run(): Unit = { - try { - while (true) { - ??? - } - } catch { - case e: InterruptedException => - // Nothing to do here, we are shutting down gracefully. - } - } - } - private val workers: List[Worker] = List.fill(poolSize)(new Worker()) - - /** Executes the given task, passed by name. */ - def execute(task: Unit => Unit): Unit = - ??? - - /** Starts the thread pool. */ - def start(): Unit = - workers.foreach(_.start()) - - /** Instantly shuts down all actively executing tasks using an interrupt. */ - def shutdown(): Unit = - workers.foreach(_.interrupt()) - } - - /** - * A queue whose take operations blocks until the queue become non-empty. - * Elements must be retrived from this queue in a last in, first out order. - * All methods of this class are thread safe, that is, they can safely - * be used from multiple thread without any particular synchronization. - */ - class BlockingQueue[T] extends AbstractBlockingQueue[T] { - - // The state of this queue is stored in an underlying List[T] defined in - // the AbstractBlockingQueue class. Your implementation should access and - // update this list using the following setter and getter methods: - // - def getUnderlying(): List[T] - // - def setUnderlying(newValue: List[T]): Unit - // Using these methods is required for testing purposes. - - /** Inserts the specified element into this queue (non-blocking) */ - def put(elem: T): Unit = - ??? - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * until an element becomes available (blocking). - * This queue operates in a last in, first out order. - */ - def take(): T = - ??? - } -} diff --git a/previous-exams/2021-midterm/m14/src/main/scala/m14/Monitor.scala b/previous-exams/2021-midterm/m14/src/main/scala/m14/Monitor.scala deleted file mode 100644 index 97dd73a6038ef6966a899da8c6b1c7dc9c9109de..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/main/scala/m14/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m14 - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/M14Suite.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/M14Suite.scala deleted file mode 100644 index cd04f2a32971eedc0e12400ae35f88d7c8f45571..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/M14Suite.scala +++ /dev/null @@ -1,159 +0,0 @@ -package m14 - -import instrumentation.SchedulableBlockingQueue -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -class M14Suite extends munit.FunSuite { - import M14._ - - test("ThreadPool should put jobs in the queue, Workers should execute jobs from the queue (10pts)") { - case class PutE(e: Unit => Unit) extends Exception - val nThreads = 3 - var taken = false - class TestBlockingQueue extends BlockingQueue[Unit => Unit] { - override def put(e: Unit => Unit): Unit = - throw new PutE(e) - - override def take(): Unit => Unit = - x => { - taken = true - Thread.sleep(10 * 1000) - } - } - - val tpe = new ThreadPoolExecutor(new TestBlockingQueue, nThreads) - val unit2unit: Unit => Unit = x => () - try { - tpe.execute(unit2unit) - assert(false, "ThreadPoolExecutor does not put jobs in the queue") - } catch { - case PutE(e) => - assert(e == unit2unit) - } - tpe.start() - Thread.sleep(1000) - assert(taken, s"ThreadPoolExecutor workers do no execute jobs from the queue") - tpe.shutdown() - } - - test("BlockingQueue should work in a sequential setting (1pts)") { - testSequential[(Int, Int, Int, Int)]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched) - queue.put(1) - queue.put(2) - queue.put(3) - queue.put(4) - (queue.take(), - queue.take(), - queue.take(), - queue.take()) - }{ tuple => - (tuple == (4, 3, 2, 1), s"Expected (4, 3, 2, 1) got $tuple") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'take' (3pts)") { - testManySchedules(2, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.take()), - args => (args(1) == 1, s"Expected 1, got ${args(1)}")) - }) - } - - test("BlockingQueue should not be able to take from an empty queue (3pts)") { - testSequential[Boolean]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched); - queue.put(1) - queue.put(2) - queue.take() - queue.take() - failsOrTimesOut(queue.take()) - }{ res => - (res, "Was able to retrieve an element from an empty queue") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take' (5pts)") { - testManySchedules(3, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.take()) - , args => { - val takeRes = args(2).asInstanceOf[Int] - val nocreation = (takeRes == 1 || takeRes == 2) - if (!nocreation) - (false, s"'take' should return either 1 or 2") - else (true, "") - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', Thread 4: 'take' (10pts)") { - testManySchedules(4, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.take(), () => queue.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(2).asInstanceOf[Int] - val takeRes2 = args(3).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 3: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 4: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - (false, s"'Thread 3 and 4' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'put(3)', Thread 4: 'take', Thread 5: 'take' (10pts)") { - testManySchedules(5, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.put(2), () => queue.put(3), - () => queue.take(), () => queue.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2, 3).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - test("BlockingQueue should work when Thread 1: 'put(1); put(2); take', Thread 2: 'put(3)', Thread 3: 'put(4)' (10pts)") { - testManySchedules(3, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List( - () => { queue.put(1); queue.put(2); queue.take() }, - () => queue.put(3), - () => queue.put(4) - ), args => { - val takeRes = args(0).asInstanceOf[Int] - val nocreation = List(1, 2, 3, 4).contains - if (!nocreation(takeRes)) - (false, s"'Thread 1: take' returned $takeRes, but should return a value in {1, 2, 3, 4}") - else if (takeRes == 1) - (false, s"'Thread 1' returned 2 before returning 1 (got $takeRes)") - else - (true, "") - }) - }) - } -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala deleted file mode 100644 index 64aa205a5e1487a2dc0d3f6dc9f4435454a5b648..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package m14 -package instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala deleted file mode 100644 index 16e68fa913f770e7b85cee2af2bdec390cb7ee4e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/SchedulableBlockingQueue.scala +++ /dev/null @@ -1,17 +0,0 @@ -package m14 -package instrumentation - -class SchedulableBlockingQueue[T](val scheduler: Scheduler) - extends m14.M14.BlockingQueue[T] with MockedMonitor { - private var underlying: List[T] = Nil - - override def getUnderlying(): List[T] = - scheduler.exec { - underlying - }(s"Get $underlying") - - override def setUnderlying(newValue: List[T]): Unit = - scheduler.exec { - underlying = newValue - }(s"Set $newValue") -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Scheduler.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Scheduler.scala deleted file mode 100644 index 448a8091eed701a6258b53110aef2ae17416afc8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Scheduler.scala +++ /dev/null @@ -1,305 +0,0 @@ -package m14 -package instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Stats.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Stats.scala deleted file mode 100644 index bc1241c543227a71727d2ca2987e3bdc9fed3210..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m14 -package instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestHelper.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestHelper.scala deleted file mode 100644 index faa3505b2d85e546e20f9f228ca0ad1f6ac9c438..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestHelper.scala +++ /dev/null @@ -1,125 +0,0 @@ -package m14 -package instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 240 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestUtils.scala b/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestUtils.scala deleted file mode 100644 index f980f99e34d653acde5590cb5e1e508607d3b61b..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m14/src/test/scala/m14/instrumentation/TestUtils.scala +++ /dev/null @@ -1,20 +0,0 @@ -package m14 -package instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm/m15.md b/previous-exams/2021-midterm/m15.md deleted file mode 100644 index dd450975e1d5b2ccebf15375e61c87c9a4519437..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15.md +++ /dev/null @@ -1,36 +0,0 @@ -## 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.** - -## Exercise - -In this question, you will implement a simple thread pool executor. -Thread pool executors provide a way to execute tasks in parallel using one of several pooled threads. -Using a pool of threads provides improved performance compared to creating a new thread for every operation since threads in the pool are reused throughout the executor's lifetime. - -Thread pool executors are one of the core primitive used to implement parallel programs. For example, they are the underlying mechanism used in the implementation of `Future`-s. - -Your task is to complete the implementation of the `ThreadPoolExecutor` class. This class' constructor takes the number of threads of the pool as argument and exposes two life-cycle methods (`start` and `shutdown`), and an `execute` method to run tasks on the thread pool. The `execute` method takes as argument `Unit => Unit` functions. These functions can be constructed anonymously using the following syntax: `val func = (x: Unit) => println("hello")`. Furthermore, given a `func` function of type `Unit => Unit`, one can invoke that function using `func(())`. -For the purpose of this exercise, you can assume that the tasks submitted to the thread pool via the `execute` method do not throw exceptions. - -The thread pool implementation uses two additional classes: -- `BlockingQueue`, used by the `ThreadPoolExecutor` to store pending tasks, -- `Worker`-s, which each run in a separate thread, consume tasks from the queue and execute those tasks. - -The `BlockingQueue` implements two methods: -- `put` to insert an element in the queue -- `take` to retrieve and remove an element from the queue, in a first in first out order. - -The `put` operation always succeeds and is non-blocking (the queue is unbounded). -The `take` operation is a potentially blocking operation that waits for new elements when called on an empty queue. - -Given that `Worker`-s run on separate threads, the `take` operation must be thread-safe. Furthermore, since the thread pool executor could also be used from multiple threads, the `put` operation should also be thread-safe. -Your implementation should use a single lock to achieve this thread safety, specifically using the `[wait](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait())`/`[notify](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify())`/`[notifyAll](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notifyAll())`/`synchronized` primitives. -Remember that `wait`, `notify` and `notifyAll` should only be invoked inside a synchronized block. diff --git a/previous-exams/2021-midterm/m15/.gitignore b/previous-exams/2021-midterm/m15/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m15/assignment.sbt b/previous-exams/2021-midterm/m15/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m15/build.sbt b/previous-exams/2021-midterm/m15/build.sbt deleted file mode 100644 index 3b7539dcef795f03ecd7ed4ffcb5eb6839054b21..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m15" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m15.M15Suite" diff --git a/previous-exams/2021-midterm/m15/grading-tests.jar b/previous-exams/2021-midterm/m15/grading-tests.jar deleted file mode 100644 index be10881c427c928b9cb66f040d9bc864841c1499..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m15/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m15/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m15/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m15/project/MOOCSettings.scala b/previous-exams/2021-midterm/m15/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m15/project/StudentTasks.scala b/previous-exams/2021-midterm/m15/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m15/project/build.properties b/previous-exams/2021-midterm/m15/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m15/project/buildSettings.sbt b/previous-exams/2021-midterm/m15/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m15/project/plugins.sbt b/previous-exams/2021-midterm/m15/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractBlockingQueue.scala b/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractBlockingQueue.scala deleted file mode 100644 index 85a28b26c1d28327725d98d501e4f855dce0f25e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractBlockingQueue.scala +++ /dev/null @@ -1,14 +0,0 @@ -package m15 - -abstract class AbstractBlockingQueue[T] extends Monitor { - private var underlying: List[T] = Nil - - def getUnderlying(): List[T] = - underlying - - def setUnderlying(newValue: List[T]): Unit = - underlying = newValue - - def put(elem: T): Unit - def take(): T -} diff --git a/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala b/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala deleted file mode 100644 index 5e663e8b70cd7482feca29b9791bcd766174ae49..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/main/scala/m15/AbstractThreadPoolExecutor.scala +++ /dev/null @@ -1,7 +0,0 @@ -package m15 - -abstract class AbstractThreadPoolExecutor { - def execute(task: Unit => Unit): Unit - def start(): Unit - def shutdown(): Unit -} diff --git a/previous-exams/2021-midterm/m15/src/main/scala/m15/M15.scala b/previous-exams/2021-midterm/m15/src/main/scala/m15/M15.scala deleted file mode 100644 index 00a4aed86504e6578a3dd70fa37bfbff7cc4bbcb..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/main/scala/m15/M15.scala +++ /dev/null @@ -1,65 +0,0 @@ -package m15 - -object M15 { - /** A thread pool that executes submitted task using one of several threads */ - class ThreadPoolExecutor(taskQueue: BlockingQueue[Unit => Unit], poolSize: Int) - extends AbstractThreadPoolExecutor { - - private class Worker extends Thread { - override def run(): Unit = { - try { - while (true) { - ??? - } - } catch { - case e: InterruptedException => - // Nothing to do here, we are shutting down gracefully. - } - } - } - private val workers: List[Worker] = List.fill(poolSize)(new Worker()) - - /** Executes the given task, passed by name. */ - def execute(task: Unit => Unit): Unit = - ??? - - /** Starts the thread pool. */ - def start(): Unit = - workers.foreach(_.start()) - - /** Instantly shuts down all actively executing tasks using an interrupt. */ - def shutdown(): Unit = - workers.foreach(_.interrupt()) - } - - /** - * A queue whose take operations blocks until the queue become non-empty. - * Elements must be retrived from this queue in a first in, first out order. - * All methods of this class are thread safe, that is, they can safely - * be used from multiple thread without any particular synchronization. - */ - class BlockingQueue[T] extends AbstractBlockingQueue[T] { - - // The state of this queue is stored in an underlying List[T] defined in - // the AbstractBlockingQueue class. Your implementation should access and - // update this list using the following setter and getter methods: - // - def getUnderlying(): List[T] - // - def setUnderlying(newValue: List[T]): Unit - // Using these methods is required for testing purposes. - - /** Inserts the specified element into this queue (non-blocking) */ - def put(elem: T): Unit = - ??? - - /** - * Retrieves and removes the head of this queue, waiting if necessary - * until an element becomes available (blocking). - * This queue operates in a first in, first out order. - */ - def take(): T = - // Hint: The .last/.init methods on List are dual of .head/.head, - // they can be used to retrive the last element and the initial part of - // the list without its last element. - ??? - } -} diff --git a/previous-exams/2021-midterm/m15/src/main/scala/m15/Monitor.scala b/previous-exams/2021-midterm/m15/src/main/scala/m15/Monitor.scala deleted file mode 100644 index b64e697d613b2d44c3f892e4ae0eebf028b5d5e8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/main/scala/m15/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m15 - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/M15Suite.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/M15Suite.scala deleted file mode 100644 index e0f2243993c4f40b8e43b0b51e1e45b8c77d2c21..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/M15Suite.scala +++ /dev/null @@ -1,281 +0,0 @@ -package m15 - -import instrumentation.SchedulableBlockingQueue -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -class M15Suite extends munit.FunSuite { - import M15._ - - test("ThreadPool should put jobs in the queue, Workers should execute jobs from the queue (10pts)") { - case class PutE(e: Unit => Unit) extends Exception - val nThreads = 3 - var taken = false - class TestBlockingQueue extends BlockingQueue[Unit => Unit] { - override def put(e: Unit => Unit): Unit = - throw new PutE(e) - - override def take(): Unit => Unit = - x => { - taken = true - Thread.sleep(10 * 1000) - } - } - - val tpe = new ThreadPoolExecutor(new TestBlockingQueue, nThreads) - val unit2unit: Unit => Unit = x => () - try { - tpe.execute(unit2unit) - assert(false, "ThreadPoolExecutor does not put jobs in the queue") - } catch { - case PutE(e) => - assert(e == unit2unit) - } - tpe.start() - Thread.sleep(1000) - assert(taken, s"ThreadPoolExecutor workers do no execute jobs from the queue") - tpe.shutdown() - } - - test("BlockingQueue should work in a sequential setting (1pts)") { - testSequential[(Int, Int, Int, Int)]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched) - queue.put(1) - queue.put(2) - queue.put(3) - queue.put(4) - (queue.take(), - queue.take(), - queue.take(), - queue.take()) - }{ tuple => - (tuple == (1, 2, 3, 4), s"Expected (1, 2, 3, 4) got $tuple") - } - } - - test("BlockingQueue should work when Thread 1: 'put(1)', Thread 2: 'take' (3pts)") { - testManySchedules(2, sched => { - val queue = new SchedulableBlockingQueue[Int](sched) - (List(() => queue.put(1), () => queue.take()), - args => (args(1) == 1, s"Expected 1, got ${args(1)}")) - }) - } - - test("BlockingQueue should not be able to take from an empty queue (3pts)") { - testSequential[Boolean]{ sched => - val queue = new SchedulableBlockingQueue[Int](sched); - queue.put(1) - queue.put(2) - queue.take() - queue.take() - failsOrTimesOut(queue.take()) - }{ res => - (res, "Was able to retrieve an element from an empty queue") - } - } - - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', and a buffer of size 1") { - testManySchedules(3, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.take()) - , args => { - val takeRes = args(2).asInstanceOf[Int] - val nocreation = (takeRes == 1 || takeRes == 2) - if (!nocreation) - (false, s"'take' should return either 1 or 2") - else (true, "") - }) - }) - } - - // testing no duplication - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'take', Thread 4: 'take', and a buffer of size 3") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(2).asInstanceOf[Int] - val takeRes2 = args(3).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 3: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 4: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - (false, s"'Thread 3 and 4' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - // testing no duplication with 5 threads - test("Should work when Thread 1: 'put(1)', Thread 2: 'put(2)', Thread 3: 'put(3)', Thread 4: 'take', Thread 5: 'take', and a buffer of size 1") { - testManySchedules(5, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => prodCons.put(1), () => prodCons.put(2), () => prodCons.put(3), - () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - val nocreation = (x: Int) => List(1, 2, 3).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3}") - - val noduplication = takeRes1 != takeRes2 - if (!noduplication) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - else (true, "") - } - m() - }) - }) - } - - // testing fifo buffer size 1 - test("Should work when Thread 1: 'put(1); put(2)', Thread 2: 'take', Thread 3: 'put(3)', Thread 4: 'put(4)', and a buffer of size 3") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(2) }, () => prodCons.take(), - () => prodCons.put(3), () => prodCons.put(4)) - , args => { - def m(): (Boolean, String) = { - val takeRes = args(1).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 3, 4).contains(x) - if (!nocreation(takeRes)) - return (false, s"'Thread 2: take' returned $takeRes, but should return a value in {1, 2, 3, 4}") - // fifo (cannot have 2 without 1) - if (takeRes == 2) - (false, s"'Thread 2' returned 2 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // testing fifo buffer size 5 - test("Should work when Thread 1: 'put(1); put(2)', Thread 2: 'take', Thread 3: 'put(11)', Thread 4: 'put(10)', and a buffer of size 5") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(2) }, () => prodCons.take(), - () => prodCons.put(11), () => prodCons.put(10)) - , args => { - def m(): (Boolean, String) = { - val takeRes = args(1).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 10, 11).contains(x) - if (!nocreation(takeRes)) - return (false, s"'Thread 2: take' returned $takeRes, but should return a value in {1, 2, 10, 11}") - // fifo (cannot have 2 without 1) - if (takeRes == 2) - (false, s"'Thread 2' returned 2 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // testing fifo on more complicated case - test("Should work when Thread 1: 'put(1); put(3)', Thread 2: 'put(2)', Thread 3: 'put(4)', Thread 4: 'take', Thread 5: 'take', and a buffer of size 10") { - testManySchedules(5, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(1); prodCons.put(3) }, () => prodCons.put(2), - () => prodCons.put(4), () => prodCons.take(), () => prodCons.take()) - , args => { - def m(): (Boolean, String) = { - val takeRes1 = args(3).asInstanceOf[Int] - val takeRes2 = args(4).asInstanceOf[Int] - // no creation - val nocreation = (x: Int) => List(1, 2, 3, 4).contains(x) - if (!nocreation(takeRes1)) - return (false, s"'Thread 4: take' returned $takeRes1 but should return a value in {1, 2, 3, 4}") - if (!nocreation(takeRes2)) - return (false, s"'Thread 5: take' returned $takeRes2 but should return a value in {1, 2, 3, 4}") - // no duplication - if (takeRes1 == takeRes2) - return (false, s"'Thread 4 and 5' returned the same value: $takeRes1") - // fifo (cannot have 3 without 1) - val takes = List(takeRes1, takeRes2) - if (takes.contains(3) && !takes.contains(1)) - (false, s"'Thread 4 or 5' returned 3 before returning 1") - else - (true, "") - } - m() - }) - }) - } - - // combining put and take in one thread - test("Should work when Thread 1: 'put(21); put(22)', Thread 2: 'take', Thread 3: 'put(23); take', Thread 4: 'put(24); take', and a buffer of size 2") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[Int](sched) - (List(() => { prodCons.put(21); prodCons.put(22) }, () => prodCons.take(), - () => { prodCons.put(23); prodCons.take() }, () => { prodCons.put(24); prodCons.take() }) - , args => { - def m(): (Boolean, String) = { - val takes = List(args(1).asInstanceOf[Int], args(2).asInstanceOf[Int], args(3).asInstanceOf[Int]) - // no creation - val vals = List(21, 22, 23, 24) - - var i = 0 - while (i < takes.length) { - val x = takes(i) - if (!vals.contains(x)) - return (false, s"'Thread $i: take' returned $x but should return a value in $vals") - i += 1 - } - - // no duplication - if (takes.distinct.size != takes.size) - return (false, s"Takes did not return unique values: $takes") - // fifo (cannot have 22 without 21) - if (takes.contains(22) && !takes.contains(21)) - (false, s"`Takes returned 22 before returning 21") - else - (true, "") - } - m() - }) - }) - } - - // completely hidden hard to crack test - test("[Black box test] Values should be taken in the order they are put") { - testManySchedules(4, sched => { - val prodCons = new SchedulableBlockingQueue[(Char, Int)](sched) - val n = 2 - (List( - () => for (i <- 1 to n) { prodCons.put(('a', i)) }, - () => for (i <- 1 to n) { prodCons.put(('b', i)) }, - () => for (i <- 1 to n) { prodCons.put(('c', i)) }, - () => { - import scala.collection.mutable - var counts = mutable.HashMap.empty[Char, Int] - counts('a') = 0 - counts('b') = 0 - counts('c') = 0 - for (i <- 1 to (3 * n)) { - val (c, n) = prodCons.take() - counts(c) += 1 - assert(counts(c) == n) - } - }) - , _ => - (true, "") - ) - }) - } -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala deleted file mode 100644 index c0591e3e03adc249e4a857600d20362bed219ba9..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,73 +0,0 @@ -package m15 -package instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala deleted file mode 100644 index 31b09bef249bc17111043612f069402ef13bdf4f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/SchedulableBlockingQueue.scala +++ /dev/null @@ -1,17 +0,0 @@ -package m15 -package instrumentation - -class SchedulableBlockingQueue[T](val scheduler: Scheduler) - extends m15.M15.BlockingQueue[T] with MockedMonitor { - private var underlying: List[T] = Nil - - override def getUnderlying(): List[T] = - scheduler.exec { - underlying - }(s"Get $underlying") - - override def setUnderlying(newValue: List[T]): Unit = - scheduler.exec { - underlying = newValue - }(s"Set $newValue") -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Scheduler.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Scheduler.scala deleted file mode 100644 index fd5f427bb86376709efeebebf0dbabc1bc96e70a..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Scheduler.scala +++ /dev/null @@ -1,305 +0,0 @@ -package m15 -package instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Stats.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Stats.scala deleted file mode 100644 index e82c09813f44c824cdfa55d54d8dd00acb584b48..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m15 -package instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestHelper.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestHelper.scala deleted file mode 100644 index 5f863382c87cb808f70a3ed4aacabec1496f15c4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestHelper.scala +++ /dev/null @@ -1,125 +0,0 @@ -package m15 -package instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 240 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestUtils.scala b/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestUtils.scala deleted file mode 100644 index 3f4afe8845bff9e2608f3b2e3b92a8739ad238cc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m15/src/test/scala/m15/instrumentation/TestUtils.scala +++ /dev/null @@ -1,20 +0,0 @@ -package m15 -package instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm/m2.md b/previous-exams/2021-midterm/m2.md deleted file mode 100644 index fb3fdb6cdbf1b3aa21b4220d71f966caaec9b9bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2.md +++ /dev/null @@ -1,55 +0,0 @@ -## 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.** - -## Exercise - -Given the following sequential implementation of a function that computes the sequence of rolling geometric means, your task will be to complete and optimize a parallel version of this code. - -```scala -/** Compute the rolling geometric mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(math.pow(x1, 1), math.pow((x1 + x2), 1.0/2), math.pow((x1 + x2 + x3), 1.0/3), ..., math.pow((x1 + x2 + x3 + ... + xn), 1.0/n))` - */ -def rollingGeoMeanParallel(arr: Arr[Int]): Arr[Double] = { - // Transform all numbers to roots with degree 1 - val arr1 = arr.map(x => Root(x, 1)) - // Compute the rolling geometric mean keeping the root structured - val arr2 = arr1.scan(Root(1, 0))((acc, x) => Root(acc.radicand * x.radicand, acc.degree + x.degree)) - // Transform the roots to Doubles - arr2.map(root => root.toDouble) - // Drop the extra initial element that was added by the scan - arr3.tail -``` - - This implementation has some issues: - - It does not use parallelism - - Creates two intermediate arrays by calling `map` - - Creates an extra intermediate arrays by calling `tail` - - Scan returns an extra element we do not need - - We want to parallelize and avoid the creation of the extra arrays. - As we are calling a `scan` the natural operations we need are `upsweep` and `downsweep`. - It is possible specialize those operations for our problem by letting those operations do the mapping. - It is also possible to change those operations to not generate the first element. - -We give you a version of `rollingGeoMeanSequential` that partially implements the parallelization using `upsweep` and `downsweep`. - - Your tasks in the exercise will be to: - - TASK 1: Implement the parallelization of `upsweep` and `downsweep` - - TASK 2: Remove the calls to the `map` - - TASK 3: Remove the call to `tail` - - You can get partial points for solving part of the tasks. - The order of the tasks is a suggestion, you may do them in any order if that is simpler for you. - -Look at the `Lib` trait to find the definitions of functions and classes you can use (or already used). -In this question we use a `Arr` array class instead of the normal `Array`. You may assume that this class has the same performance characteristics as the normal array. `Arr` provides only a limited set of operations. diff --git a/previous-exams/2021-midterm/m2/.gitignore b/previous-exams/2021-midterm/m2/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m2/assignment.sbt b/previous-exams/2021-midterm/m2/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m2/build.sbt b/previous-exams/2021-midterm/m2/build.sbt deleted file mode 100644 index 4a68d9e22fc13fac03309e5751f98bf7dd08349e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m2" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m2.M2Suite" diff --git a/previous-exams/2021-midterm/m2/grading-tests.jar b/previous-exams/2021-midterm/m2/grading-tests.jar deleted file mode 100644 index 0378ba0b46a3d1a19bbb73a2dbdf4c9b77b8cb83..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m2/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m2/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m2/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m2/project/MOOCSettings.scala b/previous-exams/2021-midterm/m2/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m2/project/StudentTasks.scala b/previous-exams/2021-midterm/m2/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m2/project/build.properties b/previous-exams/2021-midterm/m2/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m2/project/buildSettings.sbt b/previous-exams/2021-midterm/m2/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m2/project/plugins.sbt b/previous-exams/2021-midterm/m2/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m2/src/main/scala/m2/Lib.scala b/previous-exams/2021-midterm/m2/src/main/scala/m2/Lib.scala deleted file mode 100644 index 9f1aff59d87f86ee2092ec49479f388b4054a643..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/src/main/scala/m2/Lib.scala +++ /dev/null @@ -1,60 +0,0 @@ -package m2 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A number representing `radicand^(1.0/degree)` */ - case class Root(radicand: Int, degree: Int) { - def toDouble: Double = scala.math.pow(radicand, 1.0/degree) - } - - /** Tree result of an upsweep operation. Specialized for `Root` results. */ - trait TreeRes { val res: Root } - /** Leaf result of an upsweep operation. Specialized for `Root` results. */ - case class Leaf(from: Int, to: Int, res: Root) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `Root` results. */ - case class Node(left: TreeRes, res: Root, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm/m2/src/main/scala/m2/M2.scala b/previous-exams/2021-midterm/m2/src/main/scala/m2/M2.scala deleted file mode 100644 index 0fcaa856b7ce4c7615d1f3b3df58c330322a4c46..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/src/main/scala/m2/M2.scala +++ /dev/null @@ -1,89 +0,0 @@ -package m2 - - -trait M2 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling geometric mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., xn)` the result is - * `Arr(math.pow(x1, 1), math.pow((x1 + x2), 1.0/2), math.pow((x1 + x2 + x3), 1.0/3), ..., math.pow((x1 + x2 + x3 + ... + xn), 1.0/n))` - */ - def rollingGeoMeanParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - // TASK 1: Add missing parallelization in `upsweep` and `downsweep`. - // You should use the `parallel` method. - // You should use the sequential version if the number of elements is lower than THRESHOLD. - // TASK 2a: Pass `arr` to `upsweep` and `downsweep` instead of `tmp`. - // You will need to change some signatures and update the code appropriately. - // Remove the definition of `tmp` - // TASK 2b: Change the type of the array `out` from `Root` to `Double` - // You will need to change some signatures and update the code appropriately. - // Remove the call `.map(root => root.toDouble)`. - // TASK 3: Remove the call to `.tail`. - // Update the update the code appropriately. - - val tmp: Arr[Root] = arr.map(x => Root(x, 1)) - val out: Arr[Root] = Arr.ofLength(arr.length + 1) - val tree = upsweep(tmp, 0, arr.length) - downsweep(tmp, Root(1, 0), tree, out) - out(0) = Root(1, 0) - out.map(root => root.toDouble).tail - - // IDEAL SOLUTION - // val out = Arr.ofLength(arr.length) - // val tree = upsweep(arr, 0, arr.length) - // downsweep(arr, Root(1, 0), tree, out) - // out - } - - def scanOp(acc: Root, x: Root) = // No need to modify this method - Root(acc.radicand * x.radicand, acc.degree + x.degree) - - def upsweep(input: Arr[Root], from: Int, to: Int): TreeRes = { - if (to - from < 2) - Leaf(from, to, reduceSequential(input, from + 1, to, input(from))) - else { - val mid = from + (to - from) / 2 - val (tL, tR) = ( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - def downsweep(input: Arr[Root], a0: Root, tree: TreeRes, output: Arr[Root]): Unit = { - tree match { - case Node(left, _, right) => - ( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - def downsweepSequential(input: Arr[Root], from: Int, to: Int, a0: Root, output: Arr[Root]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - output(i) = a - } - } - } - - def reduceSequential(input: Arr[Root], from: Int, to: Int, a0: Root): Root = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - } - a - } -} diff --git a/previous-exams/2021-midterm/m2/src/test/scala/m2/M2Suite.scala b/previous-exams/2021-midterm/m2/src/test/scala/m2/M2Suite.scala deleted file mode 100644 index a5b3a4461ea7db8a51a48de5ee0392971a61a3b6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m2/src/test/scala/m2/M2Suite.scala +++ /dev/null @@ -1,175 +0,0 @@ -package m2 - -class M2Suite extends munit.FunSuite { - - test("Rolling geometric mean result test (5pts)") { - RollingGeoMeanBasicLogicTest.basicTests() - RollingGeoMeanBasicLogicTest.normalTests() - RollingGeoMeanBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling geometric mean parallelism test (30pts)") { - RollingGeoMeanCallsToParallel.parallelismTest() - RollingGeoMeanParallel.basicTests() - RollingGeoMeanParallel.normalTests() - RollingGeoMeanParallel.largeTests() - } - - test("[TASK 2] Rolling geometric mean no `map` test (35pts)") { - RollingGeoMeanNoMap.basicTests() - RollingGeoMeanNoMap.normalTests() - RollingGeoMeanNoMap.largeTests() - } - - test("[TASK 3] Rolling geometric mean no `tail` test (30pts)") { - RollingGeoMeanNoTail.basicTests() - RollingGeoMeanNoTail.normalTests() - RollingGeoMeanNoTail.largeTests() - } - - - object RollingGeoMeanBasicLogicTest extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingGeoMeanCallsToParallel extends M2 with LibImpl with RollingGeoMeanTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingGeoMeanParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingGeoMeanNoMap extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingGeoMeanNoTail extends M2 with LibImpl with RollingGeoMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingGeoMeanParallel extends M2 with LibImpl with RollingGeoMeanTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingGeoMeanTest extends M2 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def asSeq(arr: Arr[Double]) = - val array = new Array[Double](arr.length) - for i <- 0 to (arr.length - 1) do - array(i) = arr(i) - array.toSeq - - def scanOp_(acc: Root, x: Root) = - Root(acc.radicand * x.radicand, acc.degree + x.degree) - - def result(ds: Seq[Int]): Arr[Double] = - Arr(ds.map(x => Root(x, 1)).scan(Root(1, 0))(scanOp_).tail.map(_.toDouble): _*) - - def check(input: Seq[Int]) = - assertEquals( - // .toString calls are a terrible kludge so that NaNs compare equal to eachother... - asSeq(rollingGeoMeanParallel(Arr(input: _*))).map(_.toString), - asSeq(result(input)).map(_.toString) - ) - - def basicTests() = { - check(Seq()) - check(Seq(1)) - check(Seq(1, 2, 3, 4)) - check(Seq(4, 4, 4, 4)) - } - - def normalTests() = { - check(Seq.tabulate(64)(identity)) - check(Seq(4, 4, 4, 4)) - check(Seq(4, 8, 6, 4)) - check(Seq(4, 3, 2, 1)) - check(Seq.tabulate(64)(identity).reverse) - check(Seq.tabulate(128)(i => 128 - 2*i).reverse) - } - - def largeTests() = { - check(Seq.tabulate(500)(identity)) - check(Seq.tabulate(512)(identity)) - check(Seq.tabulate(1_000)(identity)) - check(Seq.tabulate(10_000)(identity)) - } - } -} diff --git a/previous-exams/2021-midterm/m20.md b/previous-exams/2021-midterm/m20.md deleted file mode 100644 index 78f1d3f2b5e0fa4cb7dd4da8f002402974dd2c39..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20.md +++ /dev/null @@ -1,91 +0,0 @@ -## 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.** - -## Exercise - -In this question, you will complete the definition of two concurrent data -structures **without using `synchronized`**: `SeqCount` and `MultiWriterSeqCount`. - -## Part 1: SeqCount (defined in `SeqCount.scala`) - -An instance of this class stores two integers (initially set to 0), the stored -values can be updated using `write` and retrieved using `copy`. Only one thread -at a time is allowed to call `write` but multiple threads can call `copy` at -once. - -Your task in this part is to implement `copy` such that this method never -returns _partially updated values_, for example given two threads operating -concurrently on a `SeqCount` `sc`: -```scala -// Thread 1 -sc.write(1, 2) -``` -```scala -// Thread 2 -val result = sc.copy() -``` -`result` must either be `(0, 0)` (since the initial values are 0) or `(1, 2)`, -but it must not be `(1, 0)`, `(0, 2)` or any other value. - -To successfully implement this method you will need to use `generation`: this -method returns the current value of a volatile variable which is initially set -to 0, gets incremented by one at the beginning of `write`, and incremented by -one again at the end of `write`. - -**You are not allowed to use `synchronized` or directly call any of -`myGeneration`, `myX` or `myY` (use the pre-defined getters and setters -instead).** - -Hints: -- Remember that a write to a volatile field _happens-before_ every subsequent - read of that field. -- `generation` will always be even when a write has completed and always -odd when a write is in progress. -- `copy` can be implemented as a tail-recursive method. - -## Part 2: MultiWriterSeqCount (defined in `MultiWriterSeqCount.scala`) - -Like `SeqCount`, this class stores two integers updated using `write` and -retrieved using `copy`, but unlike `SeqCount` multiple threads are allowed to -call `write` at the same time: these writes will all succeed but they are -allowed to complete in any order, for example given three threads operating -concurrently on a `MultiWriterSeqCount` `msc`: -```scala -// Thread 1 -msc.write(1, 2) -``` -```scala -// Thread 2 -msc.write(10, 20) -``` -```scala -// Thread 3 -val result = msc.copy() -``` -`result` must either be `(0, 0)`, `(1, 2)` or `(10, 20)`. - -In this class, the generation is stored in an atomic variable instead of a -volatible field therefore it's important to note that: -- a `set` on an atomic variable _happens-before_ every subsequent `get` of that - variable. -- A call to `compareAndSet` both gets and set an atomic variable. - -Your task in this part is to implement both `copy` and `write`. - -**You are not allowed to use `synchronized` or directly call any of -`myGeneration`, `myX` or `myY` (use the pre-defined getters and setters -instead).** - -Hints: -- you should be able to just copy-paste the implementation of `copy` you - implemented in Part 1 -- you will need to make use of `compareAndSetGeneration` in `write` -- `write` can be implemented as a tail-recursive method. diff --git a/previous-exams/2021-midterm/m20/.gitignore b/previous-exams/2021-midterm/m20/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m20/assignment.sbt b/previous-exams/2021-midterm/m20/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m20/build.sbt b/previous-exams/2021-midterm/m20/build.sbt deleted file mode 100644 index 8cd8c7a0320af71ee8405888adcaa8556c98574f..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m20" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m20.M20Suite" diff --git a/previous-exams/2021-midterm/m20/grading-tests.jar b/previous-exams/2021-midterm/m20/grading-tests.jar deleted file mode 100644 index 89112fdcd241e77ac54effcbaeb3c631caf37fa0..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m20/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m20/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m20/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m20/project/MOOCSettings.scala b/previous-exams/2021-midterm/m20/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m20/project/StudentTasks.scala b/previous-exams/2021-midterm/m20/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m20/project/build.properties b/previous-exams/2021-midterm/m20/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m20/project/buildSettings.sbt b/previous-exams/2021-midterm/m20/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m20/project/plugins.sbt b/previous-exams/2021-midterm/m20/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m20/src/main/scala/m20/MultiWriterSeqCount.scala b/previous-exams/2021-midterm/m20/src/main/scala/m20/MultiWriterSeqCount.scala deleted file mode 100644 index 7bb3a657410f5e706a9bf890b3e8d0483b445f45..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/main/scala/m20/MultiWriterSeqCount.scala +++ /dev/null @@ -1,46 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Multi-writer, multi-reader data structure containing a pair of integers. */ -class MultiWriterSeqCount extends Monitor: - /** Do not directly use this variable, use `generation`, `setGeneration` and - * `compareAndSetGeneration` instead. - */ - protected val myGeneration: AbstractAtomicVariable[Int] = new AtomicVariable(0) - protected def generation: Int = myGeneration.get - protected def setGeneration(newGeneration: Int): Unit = - myGeneration.set(newGeneration) - protected def compareAndSetGeneration(expected: Int, newValue: Int): Boolean = - myGeneration.compareAndSet(expected, newValue) - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def write(newX: Int, newY: Int): Unit = ??? - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def copy(): (Int, Int) = - // You should be able to just copy-paste the implementation of `copy` you - // wrote in `SeqCount` here. - ??? - -end MultiWriterSeqCount diff --git a/previous-exams/2021-midterm/m20/src/main/scala/m20/SeqCount.scala b/previous-exams/2021-midterm/m20/src/main/scala/m20/SeqCount.scala deleted file mode 100644 index 3003be40dd526ae89aa5ec93a7c2a6b7286d2d7e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/main/scala/m20/SeqCount.scala +++ /dev/null @@ -1,42 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Single-writer, multi-reader data structure containing a pair of integers. */ -class SeqCount extends Monitor: - /** Do not directly use this variable, use `generation` and `setGeneration` instead. */ - @volatile protected var myGeneration: Int = 0 - protected def generation: Int = myGeneration - protected def setGeneration(newGeneration: Int): Unit = - myGeneration = newGeneration - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method must only be called from one thread at a time. - */ - final def write(newX: Int, newY: Int): Unit = - setGeneration(generation + 1) - setX(newX) - setY(newY) - setGeneration(generation + 1) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def copy(): (Int, Int) = ??? - -end SeqCount diff --git a/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala b/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala deleted file mode 100644 index b96628365180b1e0c75d77f7adcdd9e56f718d3c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/AtomicVariable.scala +++ /dev/null @@ -1,28 +0,0 @@ -package m20.instrumentation - -import java.util.concurrent.atomic._ - -abstract class AbstractAtomicVariable[T] { - def get: T - def set(value: T): Unit - def compareAndSet(expect: T, newval: T) : Boolean -} - -class AtomicVariable[T](initial: T) extends AbstractAtomicVariable[T] { - - private val atomic = new AtomicReference[T](initial) - - override def get: T = atomic.get() - - override def set(value: T): Unit = atomic.set(value) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - val current = atomic.get - if (current == expected) { - atomic.compareAndSet(current, newValue) - } - else { - false - } - } -} diff --git a/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/Monitor.scala b/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/Monitor.scala deleted file mode 100644 index bf844ace3980d4a1da1d59c4f80870c38c563dc6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/main/scala/m20/instrumentation/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m20.instrumentation - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: =>T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/TestSuite.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/TestSuite.scala deleted file mode 100644 index 14e707c78c31a466e107cabf565f8c1f2b8ddb75..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/TestSuite.scala +++ /dev/null @@ -1,122 +0,0 @@ -package m20 - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation._ -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -enum ThreadResult: - case WriteError(error: String) - case WriteSuccess - case Read(result: (Int, Int)) -import ThreadResult._ - -class M20Suite extends munit.FunSuite: - /** If at least one thread resulted in an error, - * return `(false, errorMessage)` otherwise return `(true, "")`. - */ - def processResults(results: List[ThreadResult]): (Boolean, String) = - val success = (true, "") - results.foldLeft(success) { - case (acc @ (false, _), _) => - // Report the first error found - acc - case (_, WriteError(error)) => - (false, error) - case (_, Read((x, y))) if x + 1 != y => - (false, s"Read ($x, $y) but expected y to be ${x + 1}") - case (_, _: Read | WriteSuccess) => - success - } - - def randomList(length: Int): List[Int] = - List.fill(length)(Random.nextInt) - - test("SeqCount: single-threaded write and copy (1 pts)") { - val sc = new SeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("SeqCount: one write thread, two copy threads (4 pts)") { - testManySchedules(3, sched => - val sc = new SchedulableSeqCount(sched) - // Invariant in this test: y == x + 1 - sc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foldLeft(WriteSuccess) { - case (res: WriteError, _) => - // Report the first error found - res - case (_, i) => - sc.write(i, i + 1) - val writtenValues = (i, i + 1) - val readBack = sc.copy() - if writtenValues != readBack then - WriteError(s"Wrote $writtenValues but read back $readBack") - else - WriteSuccess - } - - def copyThread(): ThreadResult = - Read(sc.copy()) - - val threads = List( - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - test("MultiWriterSeqCount: single-threaded write and copy (1 pts)") { - val sc = new MultiWriterSeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("MultiWriterSeqCount: two write threads, two copy threads (4 pts)") { - testManySchedules(4, sched => - val msc = new SchedulableMultiWriterSeqCount(sched) - // Invariant in this test: y == x + 1 - msc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foreach(i => msc.write(i, i + 1)) - // Unlke in the SeqCount test, we do not verify that we can read back - // the values we wrote, because the other writer thread might have - // overwritten them already. - WriteSuccess - - def copyThread(): ThreadResult = - Read(msc.copy()) - - val threads = List( - () => writeThread(), - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - import scala.concurrent.duration._ - override val munitTimeout = 200.seconds -end M20Suite - diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala deleted file mode 100644 index 0b7e94fd37926fbc2c84b4a5ca8c7113a9b9d8fc..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,72 +0,0 @@ -package m20.instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Scheduler.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Scheduler.scala deleted file mode 100644 index bdc09b50f0d8ab05e89a06654034c855f98e9b3d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Scheduler.scala +++ /dev/null @@ -1,304 +0,0 @@ -package m20.instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Stats.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Stats.scala deleted file mode 100644 index e38dd2ab10b997f3e8d89fd8b9806bbb8c597e75..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package m20.instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestHelper.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestHelper.scala deleted file mode 100644 index b361ded58992134d41995527014ca62133b7e4d3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestHelper.scala +++ /dev/null @@ -1,124 +0,0 @@ -package m20.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestUtils.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestUtils.scala deleted file mode 100644 index a6a1cac480c1547251b8782042706083cbd3ce4e..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/instrumentation/TestUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package m20.instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm/m20/src/test/scala/m20/overrides.scala b/previous-exams/2021-midterm/m20/src/test/scala/m20/overrides.scala deleted file mode 100644 index cffe5c598c82933dd3a7f7bc00d810d32c582bc6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m20/src/test/scala/m20/overrides.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m20 - -import instrumentation._ - -import scala.annotation.tailrec -import java.util.concurrent.atomic._ - -class SchedulableAtomicVariable[T](initial: T, scheduler: Scheduler, name: String) extends AbstractAtomicVariable[T]: - private val proxied: AtomicVariable[T] = new AtomicVariable[T](initial) - - override def get: T = scheduler.exec { - proxied.get - } (s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - proxied.set(value) - } (s"$name: set $value", None) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - scheduler.exec { - proxied.compareAndSet(expected, newValue) - } (s"$name: compareAndSet(expected = $expected, newValue = $newValue)", Some(res => s"$name: Did it set? $res") ) - } - -end SchedulableAtomicVariable - -class SchedulableSeqCount(val scheduler: Scheduler) extends SeqCount with LockFreeMonitor: - override def generation: Int = scheduler.exec { - super.generation - } ("", Some(res => s"generation is $res")) - override def setGeneration(newGeneration: Int): Unit = scheduler.exec { - super.setGeneration(newGeneration) - } ( s"setGeneration($newGeneration)", None ) - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableSeqCount - -class SchedulableMultiWriterSeqCount(val scheduler: Scheduler) extends MultiWriterSeqCount with LockFreeMonitor: - override protected val myGeneration: AbstractAtomicVariable[Int] = new SchedulableAtomicVariable(0, scheduler, "myGeneration") - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableMultiWriterSeqCount diff --git a/previous-exams/2021-midterm/m21.md b/previous-exams/2021-midterm/m21.md deleted file mode 100644 index 82736a23664c7abba6312b6df914fedc297faf04..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21.md +++ /dev/null @@ -1,91 +0,0 @@ -## 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.** - -## Exercise - -In this question, you will complete the definition of two concurrent data -structures **without using `synchronized`**: `SeqCount` and `MultiWriterSeqCount`. - -## Part 1: SeqCount (defined in `SeqCount.scala`) - -An instance of this class stores two integers (initially set to 1), the stored -values can be updated using `write` and retrieved using `copy`. Only one thread -at a time is allowed to call `write` but multiple threads can call `copy` at -once. - -Your task in this part is to implement `copy` such that this method never -returns _partially updated values_, for example given two threads operating -concurrently on a `SeqCount` `sc`: -```scala -// Thread 1 -sc.write(1, 2) -``` -```scala -// Thread 2 -val result = sc.copy() -``` -`result` must either be `(0, 0)` (since the initial values are 0) or `(1, 2)`, -but it must not be `(1, 0)`, `(0, 2)` or any other value. - -To successfully implement this method you will need to use `generation`: this -method returns the current value of a volatile variable which is initially set -to 1, gets incremented by one at the beginning of `write`, and incremented by -one again at the end of `write`. - -**You are not allowed to use `synchronized` or directly call any of -`myGeneration`, `myX` or `myY` (use the pre-defined getters and setters -instead).** - -Hints: -- Remember that a write to a volatile field _happens-before_ every subsequent - read of that field. -- `generation` will always be odd when a write has completed and always -even when a write is in progress. -- `copy` can be implemented as a tail-recursive method. - -## Part 2: MultiWriterSeqCount (defined in `MultiWriterSeqCount.scala`) - -Like `SeqCount`, this class stores two integers updated using `write` and -retrieved using `copy`, but unlike `SeqCount` multiple threads are allowed to -call `write` at the same time: these writes will all succeed but they are -allowed to complete in any order, for example given three threads operating -concurrently on a `MultiWriterSeqCount` `msc`: -```scala -// Thread 1 -msc.write(1, 2) -``` -```scala -// Thread 2 -msc.write(10, 20) -``` -```scala -// Thread 3 -val result = msc.copy() -``` -`result` must either be `(0, 0)`, `(1, 2)` or `(10, 20)`. - -In this class, the generation is stored in an atomic variable instead of a -volatible field therefore it's important to note that: -- a `set` on an atomic variable _happens-before_ every subsequent `get` of that - variable. -- A call to `compareAndSet` both gets and set an atomic variable. - -Your task in this part is to implement both `copy` and `write`. - -**You are not allowed to use `synchronized` or directly call any of -`myGeneration`, `myX` or `myY` (use the pre-defined getters and setters -instead).** - -Hints: -- you should be able to just copy-paste the implementation of `copy` you - implemented in Part 1 -- you will need to make use of `compareAndSetGeneration` in `write` -- `write` can be implemented as a tail-recursive method. diff --git a/previous-exams/2021-midterm/m21/.gitignore b/previous-exams/2021-midterm/m21/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m21/assignment.sbt b/previous-exams/2021-midterm/m21/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m21/build.sbt b/previous-exams/2021-midterm/m21/build.sbt deleted file mode 100644 index 15c62589add717bed6163f0f77d5d607033187bf..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m21" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m21.M21Suite" diff --git a/previous-exams/2021-midterm/m21/grading-tests.jar b/previous-exams/2021-midterm/m21/grading-tests.jar deleted file mode 100644 index a8c37ec97d20d360071bd45af4e344e62720698f..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m21/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m21/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m21/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m21/project/MOOCSettings.scala b/previous-exams/2021-midterm/m21/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m21/project/StudentTasks.scala b/previous-exams/2021-midterm/m21/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m21/project/build.properties b/previous-exams/2021-midterm/m21/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m21/project/buildSettings.sbt b/previous-exams/2021-midterm/m21/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m21/project/plugins.sbt b/previous-exams/2021-midterm/m21/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m21/src/main/scala/m21/MultiWriterSeqCount.scala b/previous-exams/2021-midterm/m21/src/main/scala/m21/MultiWriterSeqCount.scala deleted file mode 100644 index bec39210798debbcfada52cddc1d291d2c41d891..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/main/scala/m21/MultiWriterSeqCount.scala +++ /dev/null @@ -1,46 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Multi-writer, multi-reader data structure containing a pair of integers. */ -class MultiWriterSeqCount extends Monitor: - /** Do not directly use this variable, use `generation`, `setGeneration` and - * `compareAndSetGeneration` instead. - */ - protected val myGeneration: AbstractAtomicVariable[Int] = new AtomicVariable(1) - protected def generation: Int = myGeneration.get - protected def setGeneration(newGeneration: Int): Unit = - myGeneration.set(newGeneration) - protected def compareAndSetGeneration(expected: Int, newValue: Int): Boolean = - myGeneration.compareAndSet(expected, newValue) - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def write(newX: Int, newY: Int): Unit = ??? - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def copy(): (Int, Int) = - // You should be able to just copy-paste the implementation of `copy` you - // wrote in `SeqCount` here. - ??? - -end MultiWriterSeqCount diff --git a/previous-exams/2021-midterm/m21/src/main/scala/m21/SeqCount.scala b/previous-exams/2021-midterm/m21/src/main/scala/m21/SeqCount.scala deleted file mode 100644 index f7a50513af3aebe478f9b9bd54ae77f919244728..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/main/scala/m21/SeqCount.scala +++ /dev/null @@ -1,42 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec - -/** Single-writer, multi-reader data structure containing a pair of integers. */ -class SeqCount extends Monitor: - /** Do not directly use this variable, use `generation` and `setGeneration` instead. */ - @volatile protected var myGeneration: Int = 1 - protected def generation: Int = myGeneration - protected def setGeneration(newGeneration: Int): Unit = - myGeneration = newGeneration - - /** Do not directly use this variable, use `x` and `setX` instead. */ - protected var myX: Int = 0 - protected def x: Int = myX - protected def setX(newX: Int): Unit = - myX = newX - - /** Do not directly use this variable, use `y` and `setY` instead. */ - protected var myY: Int = 0 - protected def y: Int = myY - protected def setY(newY: Int): Unit = - myY = newY - - /** Write new values into this data structure. - * This method must only be called from one thread at a time. - */ - final def write(newX: Int, newY: Int): Unit = - setGeneration(generation + 1) - setX(newX) - setY(newY) - setGeneration(generation + 1) - - /** Copy the values previously written into this data structure into a tuple. - * This method is always safe to call. - * The implementation of this method is not allowed to call `synchronized`. - */ - final def copy(): (Int, Int) = ??? - -end SeqCount diff --git a/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala b/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala deleted file mode 100644 index 5a5d2f4a94ad73544c265ee86d80085fcb5d48cb..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/AtomicVariable.scala +++ /dev/null @@ -1,28 +0,0 @@ -package m21.instrumentation - -import java.util.concurrent.atomic._ - -abstract class AbstractAtomicVariable[T] { - def get: T - def set(value: T): Unit - def compareAndSet(expect: T, newval: T) : Boolean -} - -class AtomicVariable[T](initial: T) extends AbstractAtomicVariable[T] { - - private val atomic = new AtomicReference[T](initial) - - override def get: T = atomic.get() - - override def set(value: T): Unit = atomic.set(value) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - val current = atomic.get - if (current == expected) { - atomic.compareAndSet(current, newValue) - } - else { - false - } - } -} diff --git a/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/Monitor.scala b/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/Monitor.scala deleted file mode 100644 index 06551000717e74916191ea0ed606405390439aca..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/main/scala/m21/instrumentation/Monitor.scala +++ /dev/null @@ -1,23 +0,0 @@ -package m21.instrumentation - -class Dummy - -trait Monitor { - implicit val dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy) = synchronizedDefault(e) - - def notify()(implicit i: Dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overriden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: =>T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() -} diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/TestSuite.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/TestSuite.scala deleted file mode 100644 index 5038092c46f6020e81887598e6e30d0f6b5d18b2..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/TestSuite.scala +++ /dev/null @@ -1,122 +0,0 @@ -package m21 - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.collection.mutable.HashMap -import scala.util.Random -import instrumentation._ -import instrumentation.TestHelper._ -import instrumentation.TestUtils._ - -enum ThreadResult: - case WriteError(error: String) - case WriteSuccess - case Read(result: (Int, Int)) -import ThreadResult._ - -class M21Suite extends munit.FunSuite: - /** If at least one thread resulted in an error, - * return `(false, errorMessage)` otherwise return `(true, "")`. - */ - def processResults(results: List[ThreadResult]): (Boolean, String) = - val success = (true, "") - results.foldLeft(success) { - case (acc @ (false, _), _) => - // Report the first error found - acc - case (_, WriteError(error)) => - (false, error) - case (_, Read((x, y))) if x + 1 != y => - (false, s"Read ($x, $y) but expected y to be ${x + 1}") - case (_, _: Read | WriteSuccess) => - success - } - - def randomList(length: Int): List[Int] = - List.fill(length)(Random.nextInt) - - test("SeqCount: single-threaded write and copy (1 pts)") { - val sc = new SeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("SeqCount: one write thread, two copy threads (4 pts)") { - testManySchedules(3, sched => - val sc = new SchedulableSeqCount(sched) - // Invariant in this test: y == x + 1 - sc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foldLeft(WriteSuccess) { - case (res: WriteError, _) => - // Report the first error found - res - case (_, i) => - sc.write(i, i + 1) - val writtenValues = (i, i + 1) - val readBack = sc.copy() - if writtenValues != readBack then - WriteError(s"Wrote $writtenValues but read back $readBack") - else - WriteSuccess - } - - def copyThread(): ThreadResult = - Read(sc.copy()) - - val threads = List( - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - test("MultiWriterSeqCount: single-threaded write and copy (1 pts)") { - val sc = new MultiWriterSeqCount - randomList(100).lazyZip(randomList(100)).foreach { (x, y) => - sc.write(x, y) - assertEquals(sc.copy(), (x, y)) - } - } - - test("MultiWriterSeqCount: two write threads, two copy threads (4 pts)") { - testManySchedules(4, sched => - val msc = new SchedulableMultiWriterSeqCount(sched) - // Invariant in this test: y == x + 1 - msc.write(0, 1) - - val randomValues = randomList(length = 5) - - def writeThread(): ThreadResult = - randomValues.foreach(i => msc.write(i, i + 1)) - // Unlke in the SeqCount test, we do not verify that we can read back - // the values we wrote, because the other writer thread might have - // overwritten them already. - WriteSuccess - - def copyThread(): ThreadResult = - Read(msc.copy()) - - val threads = List( - () => writeThread(), - () => writeThread(), - () => copyThread(), - () => copyThread() - ) - - (threads, results => processResults(results.asInstanceOf[List[ThreadResult]])) - ) - } - - import scala.concurrent.duration._ - override val munitTimeout = 200.seconds -end M21Suite - diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala deleted file mode 100644 index f7629e1b14693b723511bb67212fcdb16c64421c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,72 +0,0 @@ -package m21.instrumentation - -trait MockedMonitor extends Monitor { - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = { - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - } - override def synchronizedDefault[T](toExecute: =>T): T = { - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try { - toExecute - } finally { - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - } - } - override def notifyDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - } - scheduler.log("notify") - } - override def notifyAllDefault() = { - scheduler mapOtherStates { - state => state match { - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - } - scheduler.log("notifyAll") - } -} - -trait LockFreeMonitor extends Monitor { - override def waitDefault() = { - throw new Exception("Please use lock-free structures and do not use wait()") - } - override def synchronizedDefault[T](toExecute: =>T): T = { - throw new Exception("Please use lock-free structures and do not use synchronized()") - } - override def notifyDefault() = { - throw new Exception("Please use lock-free structures and do not use notify()") - } - override def notifyAllDefault() = { - throw new Exception("Please use lock-free structures and do not use notifyAll()") - } -} - - -abstract class ThreadState { - def locks: Seq[AnyRef] -} -trait CanContinueIfAcquiresLock extends ThreadState { - def lockToAquire: AnyRef -} -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Scheduler.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Scheduler.scala deleted file mode 100644 index cef9ac5155bd3c6747aea2f7c4d85e3616e84fbb..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Scheduler.scala +++ /dev/null @@ -1,304 +0,0 @@ -package m21.instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]) { - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = { - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the master thread if all threads have completed - if (completed.incrementAndGet() == ops.length) { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if(completed.get() != ops.length) syncObject.wait(timeout) } { time => remTime -= time } - } - if (exception.isDefined) { - exception.get - } else if (remTime <= 1) { // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - } else { - // every thing executed normally - RetVal(threadRes.toList) - } - } - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = { - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match { - case Sync(lockToAquire, locks) => - if (locks.indexOf(lockToAquire) < 0) waitForTurn else { - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - } - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - } - } - - def waitStart(): Unit = { - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if (threadStates.size < numThreads) { - wait() - } else { - notifyAll() - } - } - } - - def threadLocks = { - synchronized { - threadStates(threadId).locks - } - } - - def threadState = { - synchronized { - threadStates(threadId) - } - } - - def mapOtherStates(f: ThreadState => ThreadState) = { - val exception = threadId - synchronized { - for (k <- threadStates.keys if k != exception) { - threadStates(k) = f(threadStates(k)) - } - } - } - - def log(str: String) = { - if((realToFakeThreadId contains Thread.currentThread().getId())) { - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - opLog += s - } - } - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = { - if(! (realToFakeThreadId contains Thread.currentThread().getId())) { - primop - } else { - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if(m != "") log(m) - if (opLog.size > maxOps) - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match { - case Some(m) => log(m(res)) - case None => - } - res - } - } - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try { - realToFakeThreadId(Thread.currentThread().getId()) - } catch { - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - } - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = { - val tid = threadId - canContinue match { - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match { - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match { - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - } - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - } - } - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = { - if (!threadStates.isEmpty) { // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if (threadStates.values.forall { case e: Wait => true case _ => false }) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - } else { - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if (threadsNotBlocked.isEmpty) { - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if (threadStates.size > 1) "s" else "" - val are = if (threadStates.size > 1) "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - } else if (threadsNotBlocked.size == 1) { // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - } else { - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if (next != -1) { - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - } else { - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - } - } - } - } else canContinue - } - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = { - synchronized { - if (numThreadsWaiting.incrementAndGet() == threadStates.size) { - canContinue = decide() - notifyAll() - } - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while (!canProceed()) wait() - } - numThreadsWaiting.decrementAndGet() - } - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if (numThreadsWaiting.get() == threadStates.size) { - canContinue = decide() - notifyAll() - } - } - - def getOperationLog() = opLog -} diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Stats.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Stats.scala deleted file mode 100644 index 6eb7239c2343a77ed7f9e8193cbacc2d57a16d61..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/Stats.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2009-2015 EPFL, Lausanne */ -package m21.instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats { - def timed[T](code: => T)(cont: Long => Unit): T = { - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - } - - def withTime[T](code: => T): (T, Long) = { - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) - } -} diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestHelper.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestHelper.scala deleted file mode 100644 index 5be75d6590a34d6e7410129e66a2f2a3b17e216c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestHelper.scala +++ /dev/null @@ -1,124 +0,0 @@ -package m21.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper { - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 150 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = { - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if (threadOps.size != numThreads) - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match { - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if (!success) { - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - } - } - if (timeout <= 0) { - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - } - } - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int) { - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = { - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = { - val remOps = remainingOps(tid) - if (remOps == 0) { - liveThreads -= tid - } else { - remainingOps += (tid -> (remOps - 1)) - } - } - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match { - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - } - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if (!contexts.isEmpty) { - contexts = contexts.dropWhile(remainingOps(_) == 0) - } - val tid = contexts match { - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - } - updateState(tid) - acc :+ tid - } - schedule #:: schedules() - } - } -} diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestUtils.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestUtils.scala deleted file mode 100644 index 5da760477971e5faad31593cd61552ec2e7b4ba6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/instrumentation/TestUtils.scala +++ /dev/null @@ -1,19 +0,0 @@ -package m21.instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global - -object TestUtils { - def failsOrTimesOut[T](action: => T): Boolean = { - val asyncAction = Future { - action - } - try { - Await.result(asyncAction, 2000.millisecond) - } catch { - case _: Throwable => return true - } - return false - } -} diff --git a/previous-exams/2021-midterm/m21/src/test/scala/m21/overrides.scala b/previous-exams/2021-midterm/m21/src/test/scala/m21/overrides.scala deleted file mode 100644 index 92d0cec220a473d6e112d44ca7456037d08503b6..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m21/src/test/scala/m21/overrides.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m21 - -import instrumentation._ - -import scala.annotation.tailrec -import java.util.concurrent.atomic._ - -class SchedulableAtomicVariable[T](initial: T, scheduler: Scheduler, name: String) extends AbstractAtomicVariable[T]: - private val proxied: AtomicVariable[T] = new AtomicVariable[T](initial) - - override def get: T = scheduler.exec { - proxied.get - } (s"", Some(res => s"$name: get $res")) - - override def set(value: T): Unit = scheduler.exec { - proxied.set(value) - } (s"$name: set $value", None) - - override def compareAndSet(expected: T, newValue: T): Boolean = { - scheduler.exec { - proxied.compareAndSet(expected, newValue) - } (s"$name: compareAndSet(expected = $expected, newValue = $newValue)", Some(res => s"$name: Did it set? $res") ) - } - -end SchedulableAtomicVariable - -class SchedulableSeqCount(val scheduler: Scheduler) extends SeqCount with LockFreeMonitor: - override def generation: Int = scheduler.exec { - super.generation - } ("", Some(res => s"generation is $res")) - override def setGeneration(newGeneration: Int): Unit = scheduler.exec { - super.setGeneration(newGeneration) - } ( s"setGeneration($newGeneration)", None ) - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableSeqCount - -class SchedulableMultiWriterSeqCount(val scheduler: Scheduler) extends MultiWriterSeqCount with LockFreeMonitor: - override protected val myGeneration: AbstractAtomicVariable[Int] = new SchedulableAtomicVariable(1, scheduler, "myGeneration") - - override def x: Int = scheduler.exec { - super.x - } ("", Some(res => s"x is $res")) - override def setX(newX: Int): Unit = scheduler.exec { - super.setX(newX) - } (s"setX($newX)", None) - - override def y: Int = scheduler.exec { - super.y - } ("", Some(res => s"y is $res")) - override def setY(newY: Int): Unit = scheduler.exec { - super.setY(newY) - } (s"setY($newY)", None) - -end SchedulableMultiWriterSeqCount diff --git a/previous-exams/2021-midterm/m3.md b/previous-exams/2021-midterm/m3.md deleted file mode 100644 index 88365dc2670fdade4186d1b52204daea41bd9609..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3.md +++ /dev/null @@ -1,55 +0,0 @@ -## 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.** - -## Exercise - -Given the following sequential implementation of a function that computes the sequence of rolling windowed averages, your task will be to complete and optimize a parallel version of this code. - -```scala -/** Compute the rolling windowed mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., x_n)` the result is - * `Arr(x1, (x1+x2)/2, (x1+x2+x3)/3, (x2+x3+x4)/3, ..., (x_{n-2}, x_{n-1}, x_n)/n)` - */ -def rollingWinMeanParallel(arr: Arr[Int]): Arr[Double] = { - // Transform all numbers to averages of window of size 1 - val arr1 = arr.map(x => AvgWin(x :: Nil)) - // Compute the rolling windowed average by combining the windows together - val arr2 = arr1.scan(AvgWin(Nil))((acc, x) => acc.pushAll(x)) - // Transform the windowed averages to Doubles - arr2.map(win => win.toDouble) - // Drop the extra initial element that was added by the scan - arr3.tail -``` - - This implementation has some issues: - - It does not use parallelism - - Creates two intermediate arrays by calling `map` - - Creates an extra intermediate arrays by calling `tail` - - Scan returns an extra element we do not need - - We want to parallelize and avoid the creation of the extra arrays. - As we are calling a `scan` the natural operations we need are `upsweep` and `downsweep`. - It is possible specialize those operations for our problem by letting those operations do the mapping. - It is also possible to change those operations to not generate the first element. - -We give you a version of `rollingWinMeanSequential` that partially implements the parallelization using `upsweep` and `downsweep`. - - Your tasks in the exercise will be to: - - TASK 1: Implement the parallelization of `upsweep` and `downsweep` - - TASK 2: Remove the calls to the `map` - - TASK 3: Remove the call to `tail` - - You can get partial points for solving part of the tasks. - The order of the tasks is a suggestion, you may do them in any order if that is simpler for you. - -Look at the `Lib` trait to find the definitions of functions and classes you can use (or already used). -In this question we use a `Arr` array class instead of the normal `Array`. You may assume that this class has the same performance characteristics as the normal array. `Arr` provides only a limited set of operations. diff --git a/previous-exams/2021-midterm/m3/.gitignore b/previous-exams/2021-midterm/m3/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m3/assignment.sbt b/previous-exams/2021-midterm/m3/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m3/build.sbt b/previous-exams/2021-midterm/m3/build.sbt deleted file mode 100644 index b15645acb40417c7326345ed22ac4115e6e88735..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m3" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m3.M3Suite" diff --git a/previous-exams/2021-midterm/m3/grading-tests.jar b/previous-exams/2021-midterm/m3/grading-tests.jar deleted file mode 100644 index 01481c432fa1fc85da0c4c660daebb5f6fffd40d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m3/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m3/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m3/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m3/project/MOOCSettings.scala b/previous-exams/2021-midterm/m3/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m3/project/StudentTasks.scala b/previous-exams/2021-midterm/m3/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m3/project/build.properties b/previous-exams/2021-midterm/m3/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m3/project/buildSettings.sbt b/previous-exams/2021-midterm/m3/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m3/project/plugins.sbt b/previous-exams/2021-midterm/m3/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m3/src/main/scala/m3/Lib.scala b/previous-exams/2021-midterm/m3/src/main/scala/m3/Lib.scala deleted file mode 100644 index 68e89db2496199c75ec5362e9d9725f3c27facf5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/src/main/scala/m3/Lib.scala +++ /dev/null @@ -1,68 +0,0 @@ -package m3 - -//////////////////////////////////////// -// NO NEED TO MODIFY THIS SOURCE FILE // -//////////////////////////////////////// - -trait Lib { - - /** If an array has `n` elements and `n < THRESHOLD`, then it should be processed sequentially */ - final val THRESHOLD: Int = 33 - - /** Compute the two values in parallel - * - * Note: Most tests just compute those two sequentially to make any bug simpler to debug - */ - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) - - /** A limited array. It only contains the required operations for this exercise. */ - trait Arr[T] { - /** Get the i-th element of the array (0-based) */ - def apply(i: Int): T - /** Update the i-th element of the array with the given value (0-based) */ - def update(i: Int, x: T): Unit - /** Number of elements in this array */ - def length: Int - /** Create a copy of this array without the first element */ - def tail: Arr[T] - /** Create a copy of this array by mapping all the elements with the given function */ - def map[U](f: T => U): Arr[U] - } - - object Arr { - /** Create an array with the given elements */ - def apply[T](xs: T*): Arr[T] = { - val arr: Arr[T] = Arr.ofLength(xs.length) - for i <- 0 until xs.length do arr(i) = xs(i) - arr - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def ofLength[T](n: Int): Arr[T] = - newArrOfLength(n) - - } - - /** Create an array with the given length. All elements are initialized to `null`. */ - def newArrOfLength[T](n: Int): Arr[T] - - /** A number representing the average of a list of integers (the "window") */ - case class AvgWin(list: List[Int]) { - def push(i: Int) = list match { - case i3 :: i2 :: i1 :: Nil => AvgWin(i :: i3 :: i2 :: Nil) - case list => AvgWin(i :: list) - } - - def pushAll(other: AvgWin) = - other.list.foldRight(this)((el, self) => self.push(el)) - - def toDouble: Double = if list.isEmpty then 0 else list.sum / list.length - } - - /** Tree result of an upsweep operation. Specialized for `AvgWin` results. */ - trait TreeRes { val res: AvgWin } - /** Leaf result of an upsweep operation. Specialized for `AvgWin` results. */ - case class Leaf(from: Int, to: Int, res: AvgWin) extends TreeRes - /** Tree node result of an upsweep operation. Specialized for `AvgWin` results. */ - case class Node(left: TreeRes, res: AvgWin, right: TreeRes) extends TreeRes -} diff --git a/previous-exams/2021-midterm/m3/src/main/scala/m3/M3.scala b/previous-exams/2021-midterm/m3/src/main/scala/m3/M3.scala deleted file mode 100644 index c9b722da8dcb2ec0d381d49793b6bbcb3d0daf32..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/src/main/scala/m3/M3.scala +++ /dev/null @@ -1,89 +0,0 @@ -package m3 - - -trait M3 extends Lib { - // Functions and classes of Lib can be used in here - - /** Compute the rolling windowed mean of an array. - * - * For an array `arr = Arr(x1, x2, x3, ..., x_n)` the result is - * `Arr(x1, (x1+x2)/2, (x1+x2+x3)/3, (x2+x3+x4)/3, ..., (x_{n-2}, x_{n-1}, x_n)/3)` - */ - def rollingWinMeanParallel(arr: Arr[Int]): Arr[Double] = { - if (arr.length == 0) return Arr.ofLength(0) - // TASK 1: Add missing parallelization in `upsweep` and `downsweep`. - // You should use the `parallel` method. - // You should use the sequential version if the number of elements is lower than THRESHOLD. - // TASK 2a: Pass `arr` to `upsweep` and `downsweep` instead of `tmp`. - // You will need to change some signatures and update the code appropriately. - // Remove the definition of `tmp` - // TASK 2b: Change the type of the array `out` from `AvgWin` to `Double` - // You will need to change some signatures and update the code appropriately. - // Remove the call `.map(root => root.toDouble)`. - // TASK 3: Remove the call to `.tail`. - // Update the update the code appropriately. - - val tmp: Arr[AvgWin] = arr.map(x => AvgWin(x :: Nil)) - val out: Arr[AvgWin] = Arr.ofLength(arr.length + 1) - val tree = upsweep(tmp, 0, arr.length) - downsweep(tmp, AvgWin(Nil), tree, out) - out(0) = AvgWin(Nil) - out.map(root => root.toDouble).tail - - // IDEAL SOLUTION - // val out = Arr.ofLength(arr.length) - // val tree = upsweep(arr, 0, arr.length) - // downsweep(arr, AvgWin(Nil), tree, out) - // out - } - - def scanOp(acc: AvgWin, x: AvgWin) = // No need to modify this method - acc.pushAll(x) - - def upsweep(input: Arr[AvgWin], from: Int, to: Int): TreeRes = { - if (to - from < 2) - Leaf(from, to, reduceSequential(input, from + 1, to, input(from))) - else { - val mid = from + (to - from) / 2 - val (tL, tR) = ( - upsweep(input, from, mid), - upsweep(input, mid, to) - ) - Node(tL, scanOp(tL.res, tR.res), tR) - } - } - - def downsweep(input: Arr[AvgWin], a0: AvgWin, tree: TreeRes, output: Arr[AvgWin]): Unit = { - tree match { - case Node(left, _, right) => - ( - downsweep(input, a0, left, output), - downsweep(input, scanOp(a0, left.res), right, output) - ) - case Leaf(from, to, _) => - downsweepSequential(input, from, to, a0, output) - } - } - - def downsweepSequential(input: Arr[AvgWin], from: Int, to: Int, a0: AvgWin, output: Arr[AvgWin]): Unit = { - if (from < to) { - var i = from - var a = a0 - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - output(i) = a - } - } - } - - def reduceSequential(input: Arr[AvgWin], from: Int, to: Int, a0: AvgWin): AvgWin = { - var a = a0 - var i = from - while (i < to) { - a = scanOp(a, input(i)) - i = i + 1 - } - a - } -} diff --git a/previous-exams/2021-midterm/m3/src/test/scala/m3/M3Suite.scala b/previous-exams/2021-midterm/m3/src/test/scala/m3/M3Suite.scala deleted file mode 100644 index 176df6a14e456a6bfa29e250d20aa94253c2360b..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m3/src/test/scala/m3/M3Suite.scala +++ /dev/null @@ -1,174 +0,0 @@ -package m3 - -class M3Suite extends munit.FunSuite { - - test("Rolling windowed average result test (5pts)") { - RollingWinMeanBasicLogicTest.basicTests() - RollingWinMeanBasicLogicTest.normalTests() - RollingWinMeanBasicLogicTest.largeTests() - } - - test("[TASK 1] Rolling windowed average parallelism test (30pts)") { - RollingWinMeanCallsToParallel.parallelismTest() - RollingWinMeanParallel.basicTests() - RollingWinMeanParallel.normalTests() - RollingWinMeanParallel.largeTests() - } - - test("[TASK 2] Rolling windowed average no `map` test (35pts)") { - RollingWinMeanNoMap.basicTests() - RollingWinMeanNoMap.normalTests() - RollingWinMeanNoMap.largeTests() - } - - test("[TASK 3] Rolling windowed average no `tail` test (30pts)") { - RollingWinMeanNoTail.basicTests() - RollingWinMeanNoTail.normalTests() - RollingWinMeanNoTail.largeTests() - } - - - object RollingWinMeanBasicLogicTest extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - object RollingWinMeanCallsToParallel extends M3 with LibImpl with RollingWinMeanTest { - private var count = 0 - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = - count += 1 - (op1, op2) - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - - def parallelismTest() = { - assertParallelCount(Arr(), 0) - assertParallelCount(Arr(1), 0) - assertParallelCount(Arr(1, 2, 3, 4), 0) - assertParallelCount(Arr(Array.tabulate(16)(identity): _*), 0) - assertParallelCount(Arr(Array.tabulate(32)(identity): _*), 0) - - assertParallelCount(Arr(Array.tabulate(33)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(64)(identity): _*), 2) - assertParallelCount(Arr(Array.tabulate(128)(identity): _*), 6) - assertParallelCount(Arr(Array.tabulate(256)(identity): _*), 14) - assertParallelCount(Arr(Array.tabulate(1000)(identity): _*), 62) - assertParallelCount(Arr(Array.tabulate(1024)(identity): _*), 62) - } - - def assertParallelCount(arr: Arr[Int], expected: Int): Unit = { - try { - count = 0 - rollingWinMeanParallel(arr) - assert(count == expected, { - val extra = if (expected == 0) "" else s" ${expected/2} for the `upsweep` and ${expected/2} for the `downsweep`" - s"\n$arr\n\nERROR: Expected $expected instead of $count calls to `parallel(...)` for an array of ${arr.length} elements. Current parallel threshold is $THRESHOLD.$extra" - }) - } finally { - count = 0 - } - } - - } - - object RollingWinMeanNoMap extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def map[U](f: T => U): Arr[U] = throw Exception("Should not call Arr.map") - } - } - - object RollingWinMeanNoTail extends M3 with LibImpl with RollingWinMeanTest { - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = (op1, op2) - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl[T](arr) { - override def tail: Arr[T] = throw Exception("Should not call Arr.tail") - } - } - - object RollingWinMeanParallel extends M3 with LibImpl with RollingWinMeanTest { - import scala.concurrent.duration._ - val TIMEOUT = Duration(10, SECONDS) - def parallel[T1, T2](op1: => T1, op2: => T2): (T1, T2) = { - import concurrent.ExecutionContext.Implicits.global - import scala.concurrent._ - Await.result(Future(op1).zip(Future(op2)), TIMEOUT) // FIXME not timing-out - } - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] = new ArrImpl(arr) - } - - trait LibImpl extends Lib { - - def newArrFrom[T](arr: Array[AnyRef]): Arr[T] - - def newArrOfLength[T](n: Int): Arr[T] = - newArrFrom(new Array(n)) - - class ArrImpl[T](val arr: Array[AnyRef]) extends Arr[T]: - def apply(i: Int): T = - arr(i).asInstanceOf[T] - def update(i: Int, x: T): Unit = - arr(i) = x.asInstanceOf[AnyRef] - def length: Int = - arr.length - def map[U](f: T => U): Arr[U] = - newArrFrom(arr.map(f.asInstanceOf[AnyRef => AnyRef])) - def tail: Arr[T] = - newArrFrom(arr.tail) - override def toString: String = - arr.mkString("Arr(", ", ", ")") - override def equals(that: Any): Boolean = - that match - case that: ArrImpl[_] => Array.equals(arr, that.arr) - case _ => false - } - - trait RollingWinMeanTest extends M3 { - - def tabulate[T](n: Int)(f: Int => T): Arr[T] = - val arr = Arr.ofLength[T](n) - for i <- 0 until n do - arr(i) = f(i) - arr - - def asSeq(arr: Arr[Double]) = - val array = new Array[Double](arr.length) - for i <- 0 to (arr.length - 1) do - array(i) = arr(i) - array.toSeq - - def scanOp_(acc: AvgWin, x: AvgWin) = - acc.pushAll(x) - - def result(ds: Seq[Int]): Arr[Double] = - Arr(ds.map(x => AvgWin(x :: Nil)).scan(AvgWin(Nil))(scanOp_).tail.map(_.toDouble): _*) - - def check(input: Seq[Int]) = - assertEquals( - asSeq(rollingWinMeanParallel(Arr(input: _*))), - asSeq(result(input)) - ) - - def basicTests() = { - check(Seq()) - check(Seq(1)) - check(Seq(1, 2, 3, 4)) - check(Seq(4, 4, 4, 4)) - } - - def normalTests() = { - check(Seq.tabulate(64)(identity)) - check(Seq(4, 4, 4, 4)) - check(Seq(4, 8, 6, 4)) - check(Seq(4, 3, 2, 1)) - check(Seq.tabulate(64)(identity).reverse) - check(Seq.tabulate(128)(i => 128 - 2*i).reverse) - } - - def largeTests() = { - check(Seq.tabulate(500)(identity)) - check(Seq.tabulate(512)(identity)) - check(Seq.tabulate(1_000)(identity)) - check(Seq.tabulate(10_000)(identity)) - } - } -} diff --git a/previous-exams/2021-midterm/m6.md b/previous-exams/2021-midterm/m6.md deleted file mode 100644 index 6280bbb4202df0f0595b58e76a31a4182b96a6c4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6.md +++ /dev/null @@ -1,149 +0,0 @@ -## 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.** - -## Exercise - -In this exercise, you will implement an array Combiner using internally a doubly linked list of arrays. Your goal is to complete the implementation of the (simplified) Combiner interface, by implementing the `result` method to compute the result array from this array combiner. - -Here you can see the declaration of the `DLLCombiner` class and the related `Node` class definition. Look at the `Lib` trait in the `lib.scala` file to find all definitions of relevant functions and classes. - - -```scala - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) -``` - -`DLLCombiner` class contains the implementation of methods `+=` and `combine`. You should look at them to better understand the structure of this array Combiner, before moving on to solving this exercise. - -Your task in the exercise will be to implement the `result` method of the `DLLCombinerImplementation` class. This method should compute the result array from this array combiner. This method should work in parallel according to the Combiner contract. Implement this method efficiently using 4 parallel tasks, by copying the doubly linked list to the array from both ends at the same time. Two threads should start from the start of the list and two from the end. In each case, one thread would be responsible for odd list indexes and the other for even ones. - - -```scala - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size) { - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task1(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task2(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - def task3(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]) = { - ??? - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - ??? - - data - } - - } -``` - -Following the description above, your task in the exercise is to: - -- Implement the four tasks to copy parts of the array. Each task is responsible for computing one quarter of the array, as indicated in comments: - + Task 1: Computes every other Integer element of data array, starting from the first (index 0), up to the middle - + Task 2: Computes every other Integer element of data array, starting from the second, up to the middle - + Task 3: Computes every other Integer element of data array, starting from the second to last, up to the middle - + Task 4: Computes every other Integer element of data array, starting from the last, up to the middle -- Implement the method `result` to compute the result array in parallel using those four tasks. - -Hints: - -- Note that this doubly linked list implementation uses `null` pointers to represent the absence of nodes. Be careful when working with `null` pointers in your solution, to avoid causing a `NullPointerException`. - -- `DLLCombinerImplementation` comes with a private `copyForward` method that you can use in your solution: - -```scala - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) -``` - -This method copies certain elements from a doubly linked list to an array, in a way that might be useful for this exercise. - -## Examples - -Here is one example of the `result` method with intermediate results: - -```scala - val combiner1 = DLLCombinerImplementation(4) - combiner1 += 7 // (7) - combiner1 += 2 // (7, 2) - combiner1 += 4 // (7, 2, 4) - combiner1 += 3 // (7, 2, 4, 3) - combiner1 += 9 // (7, 2, 4, 3) <-> (9) - combiner1 += 5 // (7, 2, 4, 3) <-> (9, 5) - combiner1 += 1 // (7, 2, 4, 3) <-> (9, 5, 1) - - val res1 = combiner1.result() // (7, 2, 4, 3, 9, 5, 1) - -``` -In this example, `task1` was responsible for computing elements at indexes 0 and 2, `task2` for computing the element at index 1, `task3` for computing elements at indexes 5 and 3, and `task4` for computing elements at indexes 6 and 4. - -Here is another example with combining: - -```scala - val c1 = DLLCombinerImplementation(4) - c1 += 7 // (7) - c1 += 2 // (7, 2) - c1 += 4 // (7, 2, 4) - c1 += 3 // (7, 2, 4, 3) - c1 += 9 // (7, 2, 4, 3) <-> (9) - c1 += 5 // (7, 2, 4, 3) <-> (9, 5) - c1 += 1 // (7, 2, 4, 3) <-> (9, 5, 1) - - val c2 = DLLCombinerImplementation(4) - c2 += 6 // (6) - c2 += 8 // (6, 8) - c2 += 5 // (6, 8, 5) - c2 += 1 // (6, 8, 5, 1) - - val c3 = DLLCombinerImplementation(4) - c3 += 1 // (1) - - c1.combine(c2).combine(c3) // (7, 2, 4, 3) <-> (9, 5, 1) <-> (6, 8, 5, 1) <-> (1) - val res = c1.result() // (7, 2, 4, 3, 9, 5, 1, 6, 8, 5, 1, 1) - -``` - -You can look at the public tests to find more examples. - -In your solution you should only make changes to the `DLLCombinerImplementation` class. You are not allowed to change the file `lib.scala`. You can get partial points for solving parts of this exercise. - - - diff --git a/previous-exams/2021-midterm/m6/.gitignore b/previous-exams/2021-midterm/m6/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m6/assignment.sbt b/previous-exams/2021-midterm/m6/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m6/build.sbt b/previous-exams/2021-midterm/m6/build.sbt deleted file mode 100644 index 96606f6e8cb06d2e80e604e6d720bfbd3a83819c..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m6" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m6.M6Suite" diff --git a/previous-exams/2021-midterm/m6/grading-tests.jar b/previous-exams/2021-midterm/m6/grading-tests.jar deleted file mode 100644 index cdd54531b11cad5a6a0cb6060a4495ca86da20c0..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m6/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m6/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m6/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m6/project/MOOCSettings.scala b/previous-exams/2021-midterm/m6/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m6/project/StudentTasks.scala b/previous-exams/2021-midterm/m6/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m6/project/build.properties b/previous-exams/2021-midterm/m6/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m6/project/buildSettings.sbt b/previous-exams/2021-midterm/m6/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m6/project/plugins.sbt b/previous-exams/2021-midterm/m6/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m6/src/main/scala/m6/M6.scala b/previous-exams/2021-midterm/m6/src/main/scala/m6/M6.scala deleted file mode 100644 index 4e54913310d29d409c3bd5bb3512f2634f8297be..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/src/main/scala/m6/M6.scala +++ /dev/null @@ -1,69 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait M6 extends Lib { - - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size){ - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task1(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task2(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - def task3(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]): Unit = { - ??? - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - ??? - - data - } - - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to < limit) { - try { - data(i_to) = current.value(i_from) - i_to += 2 - i_from += 2 - if(i_from == current.cnt){ - current = current.next - i_from = 0 - } - else if(i_from > current.cnt) { - current = current.next - i_from = 1 - if(current.cnt == 1) { - current = current.next - i_from = 0 - } - } - } - catch{ - case e: Exception => - } - } - } - } - -} diff --git a/previous-exams/2021-midterm/m6/src/main/scala/m6/lib.scala b/previous-exams/2021-midterm/m6/src/main/scala/m6/lib.scala deleted file mode 100644 index bfb28387fa6826b708bc35f3aa47417be7064840..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/src/main/scala/m6/lib.scala +++ /dev/null @@ -1,84 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait Lib { - - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) { - var head: Node = null - var last: Node = null - var cnt: Int = 0 - var chunks: Int = 0 - - // Adds an Integer to the last node of this array combiner. If the last node is full, allocates a new node. - def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - // Combines this array combiner and another given combiner in constant O(1) complexity. - def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - - def task1(data: Array[Int]): ForkJoinTask[Unit] - def task2(data: Array[Int]): ForkJoinTask[Unit] - def task3(data: Array[Int]): ForkJoinTask[Unit] - def task4(data: Array[Int]): Unit - - def result(): Array[Int] - - } - - def task[T](body: => T): ForkJoinTask[T] - -} \ No newline at end of file diff --git a/previous-exams/2021-midterm/m6/src/test/scala/m6/M6Suite.scala b/previous-exams/2021-midterm/m6/src/test/scala/m6/M6Suite.scala deleted file mode 100644 index e04fcf064cb9f9c7262b90f94365cd4651fa49d0..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m6/src/test/scala/m6/M6Suite.scala +++ /dev/null @@ -1,422 +0,0 @@ -package m6 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -class M6Suite extends AbstractM6Suite { - - // (70+) 30 / 500 points for correct implementation, don't check parallelism - test("[Correctness] fetch result - simple combiners (5pts)") { - assertCorrectnessSimple() - } - - test("[Correctness] fetch result - small combiners (5pts)") { - assertCorrectnessBasic() - } - - test("[Correctness] fetch result - small combiners after combining (10pts)") { - assertCorrectnessCombined() - } - - test("[Correctness] fetch result - large combiners (10pts)") { - assertCorrectnessLarge() - } - - def assertCorrectnessSimple() = { - simpleCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessBasic() = { - basicCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessCombined() = { - combinedCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessLarge() = { - largeCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - // (70+30+) 50 / 500 points for correct parallel implementation, don't check if it's exactly 1/4 of the array per task - private var count = 0 - private val expected = 3 - - override def task[T](body: => T): ForkJoinTask[T] = { - count += 1 - scheduler.value.schedule(body) - } - - test("[TaskCount] number of newly created tasks should be 3 (5pts)") { - assertTaskCountSimple() - } - - test("[TaskCount] fetch result and check parallel - simple combiners (5pts)") { - assertTaskCountSimple() - assertCorrectnessSimple() - } - - test("[TaskCount] fetch result and check parallel - small combiners (10pts)") { - assertTaskCountSimple() - assertCorrectnessBasic() - } - - test("[TaskCount] fetch result and check parallel - small combiners after combining (15pts)") { - assertTaskCountSimple() - assertCorrectnessCombined() - } - - test("[TaskCount] fetch result and check parallel - large combiners (15pts)") { - assertTaskCountSimple() - assertCorrectnessLarge() - } - - def assertTaskCountSimple(): Unit = { - simpleCombiners.foreach(elem => assertTaskCount(elem._1, elem._2)) - } - - def assertTaskCount(combiner: DLLCombinerTest, array: Array[Int]): Unit = { - try { - count = 0 - build(combiner, array) - combiner.result() - assertEquals(count, expected, { - s"ERROR: Expected $expected instead of $count calls to `task(...)`" - }) - } finally { - count = 0 - } - } - - //(70+30+50+) 200 / 500 points for correct parallel implementation, exactly 1/4 of the array per task - test("[TaskFairness] each task should compute 1/4 of the result (50pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - simple combiners (20pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - assertCorrectnessSimple() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners (30pts)") { - assertTaskFairness(basicCombiners.unzip._1) - assertCorrectnessBasic() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners after combining (50pts)") { - assertTaskFairness(combinedCombiners.unzip._1) - assertCorrectnessCombined() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - large combiners (50pts)") { - assertTaskFairness(largeCombiners.unzip._1) - assertCorrectnessLarge() - } - - def assertTaskFairness(combiners: List[DLLCombinerTest]): Unit = { - def assertNewTaskFairness(combiner: DLLCombinerTest, task: ForkJoinTask[Unit], data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - task.join - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - def assertMainTaskFairness(combiner: DLLCombinerTest, task: Unit, data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - combiners.foreach { elem => - var data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task1(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task2(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task3(data), data) - - data = Array.fill(elem.cnt)(0) - assertMainTaskFairness(elem, elem.task4(data), data) - } - } - - //(70+30+50+200+) 150 / 500 points for correct parallel implementation, exactly 1/4 of the array per task, exactly the specified quarter - - test("[TaskPrecision] each task should compute specified 1/4 of the result - simple combiners (20pts)") { - assertTaskPrecision(simpleCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners (30pts)") { - assertTaskPrecision(basicCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners after combining (50pts)") { - assertTaskPrecision(combinedCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - large combiners (50pts)") { - assertTaskPrecision(largeCombiners) - } - - def assertTaskPrecision(combiners: List[(DLLCombinerTest, Array[Int])]): Unit = { - combiners.foreach { elem => - var data = Array.fill(elem._1.cnt)(0) - var ref = Array.fill(elem._1.cnt)(0) - val task1 = elem._1.task1(data) - task1.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 0) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task2 = elem._1.task2(data) - task2.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 1) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task3 = elem._1.task3(data) - task3.join - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 == elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task4 = elem._1.task4(data) - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 != elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - } - } - - test("[Public] fetch simple result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1, 2, 3, 8) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result after simple combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - - val combiner2 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 8 - - val combiner3 = DLLCombinerTest(2) - combiner2 += 1 - combiner2 += 9 - - val combiner4 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 2 - - val result = combiner1.combine(combiner2).combine(combiner3).combine(combiner4).result() - val array = Array(7, 2, 3, 8, 1, 9, 3, 2) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result - empty combiner (20pts)") { - val combiner1 = DLLCombinerTest(2) - val result = combiner1.result() - assertEquals(result.size, 0) - } - - test("[Public] fetch result - full single element combiner (15pts)") { - val combiner1 = DLLCombinerTest(3) - combiner1 += 4 - combiner1 += 2 - combiner1 += 6 - - val result = combiner1.result() - val array = Array(4, 2, 6) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - -} - - -trait AbstractM6Suite extends munit.FunSuite with LibImpl { - - def simpleCombiners = buildSimpleCombiners() - def basicCombiners = buildBasicCombiners() - def combinedCombiners = buildCombinedCombiners() - def largeCombiners = buildLargeCombiners() - - def buildSimpleCombiners() = { - val simpleCombiners = List( - (DLLCombinerTest(4), Array(4, 2, 6, 1, 5, 4, 3, 5, 6, 3, 4, 5, 6, 3, 4, 5)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2)), - (DLLCombinerTest(4), Array.fill(16)(5)) - ) - simpleCombiners.foreach(elem => build(elem._1, elem._2)) - simpleCombiners - } - - def buildBasicCombiners() = { - val basicCombiners = List( - (DLLCombinerTest(2), Array(4, 2, 6)), - (DLLCombinerTest(5), Array(4, 2, 6)), - (DLLCombinerTest(3), Array(4, 2, 6, 1, 7, 2, 4)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 11, 12, 13, 14, 15, 16, 17, 22)), - (DLLCombinerTest(3), Array.fill(16)(7)), - (DLLCombinerTest(3), Array.fill(19)(7)), - (DLLCombinerTest(3), Array.fill(5)(7)), - (DLLCombinerTest(3), Array.fill(6)(7)) - ) - basicCombiners.foreach(elem => build(elem._1, elem._2)) - basicCombiners - } - - def buildCombinedCombiners() = { - var combinedCombiners = List[(DLLCombinerTest, Array[Int])]() - Range(1, 10).foreach { chunk_size => - val array = basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foldLeft(Array[Int]()) { (acc, i) => acc ++ i._2 } - val combiner = DLLCombinerTest(chunk_size) - basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foreach(elem => combiner.combine(elem._1)) - - combinedCombiners = combinedCombiners :+ (combiner, array) - } - combinedCombiners - } - - def buildLargeCombiners() = { - val largeCombiners = List( - (DLLCombinerTest(21), Array.fill(1321)(4) ++ Array.fill(1322)(7)), - (DLLCombinerTest(18), Array.fill(1341)(2) ++ Array.fill(1122)(5)), - (DLLCombinerTest(3), Array.fill(1321)(4) ++ Array.fill(1322)(7) ++ Array.fill(321)(4) ++ Array.fill(322)(7)), - (DLLCombinerTest(12), Array.fill(992321)(4) ++ Array.fill(99322)(7)), - (DLLCombinerTest(4), Array.fill(953211)(4) ++ Array.fill(999322)(1)) - ) - largeCombiners.foreach(elem => build(elem._1, elem._2)) - largeCombiners - } - - def build(combiner: DLLCombinerTest, array: Array[Int]): DLLCombinerTest = { - array.foreach(elem => combiner += elem) - combiner - } - - def compare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - val result = combiner.result() - Range(0,array.size).forall(i => array(i) == result(i)) - } - - def buildAndCompare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - array.foreach(elem => combiner += elem) - val result = combiner.result() - - Range(0,array.size).forall(i => array(i) == result(i)) - } - -} - -trait LibImpl extends M6 { - - val forkJoinPool = new ForkJoinPool - - abstract class TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] - } - - class DefaultTaskScheduler extends TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] = { - val t = new RecursiveTask[T] { - def compute = body - } - Thread.currentThread match { - case wt: ForkJoinWorkerThread => - t.fork() - case _ => - forkJoinPool.execute(t) - } - t - } - } - - val scheduler = - new DynamicVariable[TaskScheduler](new DefaultTaskScheduler) - - def task[T](body: => T): ForkJoinTask[T] = { - scheduler.value.schedule(body) - } - - class DLLCombinerTest(chunk_size: Int = 3) extends DLLCombinerImplementation(chunk_size) { - - override def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - override def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - } -} diff --git a/previous-exams/2021-midterm/m7.md b/previous-exams/2021-midterm/m7.md deleted file mode 100644 index 45a74f060eb38b9d95195c1eeaedd1bfa9dd06ed..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7.md +++ /dev/null @@ -1,149 +0,0 @@ -## 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.** - -## Exercise - -In this exercise, you will implement an array Combiner using internally a doubly linked list of arrays. Your goal is to complete the implementation of the (simplified) Combiner interface, by implementing the `result` method to compute the result array from this array combiner. - -Here you can see the declaration of the `DLLCombiner` class and the related `Node` class definition. Look at the `Lib` trait in the `lib.scala` file to find all definitions of relevant functions and classes. - - -```scala - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) -``` - -`DLLCombiner` class contains the implementation of methods `+=` and `combine`. You should look at them to better understand the structure of this array Combiner, before moving on to solving this exercise. - -Your task in the exercise will be to implement the `result` method of the `DLLCombinerImplementation` class. This method should compute the result array from this array combiner. This method should work in parallel according to the Combiner contract. Implement this method efficiently using 4 parallel tasks, by copying the doubly linked list to the array from both ends at the same time. Two threads should start from the start of the list and two from the end. In each case, one thread would be responsible for odd list indexes and the other for even ones. - - -```scala - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size) { - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task1(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task2(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - def task3(data: Array[Int]) = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]) = { - ??? - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - ??? - - data - } - - } -``` - -Following the description above, your task in the exercise is to: - -- Implement the four tasks to copy parts of the array. Each task is responsible for computing one quarter of the array, as indicated in comments: - + Task 1: Computes every other Integer element of data array, starting from the second, up to the middle - + Task 2: Computes every other Integer element of data array, starting from the first (index 0), up to the middle - + Task 3: Computes every other Integer element of data array, starting from the last, up to the middle - + Task 4: Computes every other Integer element of data array, starting from the second to last, up to the middle -- Implement the method `result` to compute the result array in parallel using those four tasks. - -Hints: - -- Note that this doubly linked list implementation uses `null` pointers to represent the absence of nodes. Be careful when working with `null` pointers in your solution, to avoid causing a `NullPointerException`. - -- `DLLCombinerImplementation` comes with a private `copyForward` method that you can use in your solution: - -```scala - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) -``` - -This method copies certain elements from a doubly linked list to an array, in a way that might be useful for this exercise. - -## Examples - -Here is one example of the `result` method with intermediate results: - -```scala - val combiner1 = DLLCombinerImplementation(4) - combiner1 += 7 // (7) - combiner1 += 2 // (7, 2) - combiner1 += 4 // (7, 2, 4) - combiner1 += 3 // (7, 2, 4, 3) - combiner1 += 9 // (7, 2, 4, 3) <-> (9) - combiner1 += 5 // (7, 2, 4, 3) <-> (9, 5) - combiner1 += 1 // (7, 2, 4, 3) <-> (9, 5, 1) - - val res1 = combiner1.result() // (7, 2, 4, 3, 9, 5, 1) - -``` -In this example, `task1` was responsible for computing elements at index 1, `task2` for computing elements at indexes 0 and 2, `task3` for computing elements at indexes 6 and 4, and `task4` for computing elements at indexes 5 and 3. - -Here is another example with combining: - -```scala - val c1 = DLLCombinerImplementation(4) - c1 += 7 // (7) - c1 += 2 // (7, 2) - c1 += 4 // (7, 2, 4) - c1 += 3 // (7, 2, 4, 3) - c1 += 9 // (7, 2, 4, 3) <-> (9) - c1 += 5 // (7, 2, 4, 3) <-> (9, 5) - c1 += 1 // (7, 2, 4, 3) <-> (9, 5, 1) - - val c2 = DLLCombinerImplementation(4) - c2 += 6 // (6) - c2 += 8 // (6, 8) - c2 += 5 // (6, 8, 5) - c2 += 1 // (6, 8, 5, 1) - - val c3 = DLLCombinerImplementation(4) - c3 += 1 // (1) - - c1.combine(c2).combine(c3) // (7, 2, 4, 3) <-> (9, 5, 1) <-> (6, 8, 5, 1) <-> (1) - val res = c1.result() // (7, 2, 4, 3, 9, 5, 1, 6, 8, 5, 1, 1) - -``` - -You can look at the public tests to find more examples. - -In your solution you should only make changes to the `DLLCombinerImplementation` class. You are not allowed to change the file `lib.scala`. You can get partial points for solving parts of this exercise. - - - diff --git a/previous-exams/2021-midterm/m7/.gitignore b/previous-exams/2021-midterm/m7/.gitignore deleted file mode 100644 index 40937dc9b192820d0ede18efd3c7e6442a083b17..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# General -*.DS_Store -*.swp -*~ - -# Dotty -*.class -*.tasty -*.hasTasty - -# sbt -target/ - -# IDE -.bsp -.bloop -.metals -.vscode - -# datasets -stackoverflow-grading.csv -wikipedia-grading.dat diff --git a/previous-exams/2021-midterm/m7/assignment.sbt b/previous-exams/2021-midterm/m7/assignment.sbt deleted file mode 100644 index da7eb3c8347293a18da0025fcd6060d8f8f7cc11..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/assignment.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// Student tasks (i.e. submit, packageSubmission) -enablePlugins(StudentTasks) diff --git a/previous-exams/2021-midterm/m7/build.sbt b/previous-exams/2021-midterm/m7/build.sbt deleted file mode 100644 index 25a0926a0020518f0905ffb468b8daccfb2489c4..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -course := "midterm" -assignment := "m7" -scalaVersion := "3.0.0-RC1" -scalacOptions ++= Seq("-language:implicitConversions", "-deprecation") - -libraryDependencies += "org.scalameta" %% "munit" % "0.7.22" - -val MUnitFramework = new TestFramework("munit.Framework") -testFrameworks += MUnitFramework -// Decode Scala names -testOptions += Tests.Argument(MUnitFramework, "-s") -testSuite := "m7.M7Suite" diff --git a/previous-exams/2021-midterm/m7/grading-tests.jar b/previous-exams/2021-midterm/m7/grading-tests.jar deleted file mode 100644 index 4260440385397b26a3f9b531aac5592925d392b3..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm/m7/grading-tests.jar and /dev/null differ diff --git a/previous-exams/2021-midterm/m7/project/FilteringReporterPlugin.scala b/previous-exams/2021-midterm/m7/project/FilteringReporterPlugin.scala deleted file mode 100644 index 2e4fd9a4d998698cd52643344b33a5e719dd7971..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/FilteringReporterPlugin.scala +++ /dev/null @@ -1,31 +0,0 @@ -package sbt // To access the private[sbt] compilerReporter key -package filteringReporterPlugin - -import Keys._ -import ch.epfl.lamp._ - -object FilteringReporterPlugin extends AutoPlugin { - override lazy val projectSettings = Seq( - // Turn off warning coming from scalameter that we cannot fix without changing scalameter - compilerReporter in (Compile, compile) ~= { reporter => new FilteringReporter(reporter) } - ) -} - -class FilteringReporter(reporter: xsbti.Reporter) extends xsbti.Reporter { - - def reset(): Unit = reporter.reset() - def hasErrors: Boolean = reporter.hasErrors - def hasWarnings: Boolean = reporter.hasWarnings - def printSummary(): Unit = reporter.printSummary() - def problems: Array[xsbti.Problem] = reporter.problems - - def log(problem: xsbti.Problem): Unit = { - if (!problem.message.contains("An existential type that came from a Scala-2 classfile cannot be")) - reporter.log(problem) - } - - def comment(pos: xsbti.Position, msg: String): Unit = - reporter.comment(pos, msg) - - override def toString = s"CollectingReporter($reporter)" -} diff --git a/previous-exams/2021-midterm/m7/project/MOOCSettings.scala b/previous-exams/2021-midterm/m7/project/MOOCSettings.scala deleted file mode 100644 index 1c40443a53085d23fadb134f4e1a505c32231f1d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/MOOCSettings.scala +++ /dev/null @@ -1,49 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import sbt.Keys._ - -/** - * Coursera uses two versions of each assignment. They both have the same assignment key and part id but have - * different item ids. - * - * @param key Assignment key - * @param partId Assignment partId - * @param itemId Item id of the non premium version - * @param premiumItemId Item id of the premium version (`None` if the assignment is optional) - */ -case class CourseraId(key: String, partId: String, itemId: String, premiumItemId: Option[String]) - -/** - * Settings shared by all assignments, reused in various tasks. - */ -object MOOCSettings extends AutoPlugin { - - override def requires = super.requires && filteringReporterPlugin.FilteringReporterPlugin - - object autoImport { - val course = SettingKey[String]("course") - val assignment = SettingKey[String]("assignment") - val options = SettingKey[Map[String, Map[String, String]]]("options") - val courseraId = settingKey[CourseraId]("Coursera-specific information identifying the assignment") - val testSuite = settingKey[String]("Fully qualified name of the test suite of this assignment") - .withRank(KeyRanks.Invisible) - // Convenient alias - type CourseraId = ch.epfl.lamp.CourseraId - val CourseraId = ch.epfl.lamp.CourseraId - } - - import autoImport._ - - override val globalSettings: Seq[Def.Setting[_]] = Seq( - // supershell is verbose, buggy and useless. - useSuperShell := false - ) - - override val projectSettings: Seq[Def.Setting[_]] = Seq( - parallelExecution in Test := false, - // Report test result after each test instead of waiting for every test to finish - logBuffered in Test := false, - name := s"${course.value}-${assignment.value}" - ) -} diff --git a/previous-exams/2021-midterm/m7/project/StudentTasks.scala b/previous-exams/2021-midterm/m7/project/StudentTasks.scala deleted file mode 100644 index c4669afe82dd2b45651f94dcad9e736f29d21432..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/StudentTasks.scala +++ /dev/null @@ -1,303 +0,0 @@ -package ch.epfl.lamp - -import sbt._ -import Keys._ - -// import scalaj.http._ -import java.io.{File, FileInputStream, IOException} -import org.apache.commons.codec.binary.Base64 -// import play.api.libs.json.{Json, JsObject, JsPath} -import scala.util.{Failure, Success, Try} - -/** - * Provides tasks for submitting the assignment - */ -object StudentTasks extends AutoPlugin { - - override def requires = super.requires && MOOCSettings - - object autoImport { - val packageSourcesOnly = TaskKey[File]("packageSourcesOnly", "Package the sources of the project") - val packageBinWithoutResources = TaskKey[File]("packageBinWithoutResources", "Like packageBin, but without the resources") - val packageSubmissionZip = TaskKey[File]("packageSubmissionZip") - val packageSubmission = inputKey[Unit]("package solution as an archive file") - - lazy val Grading = config("grading") extend(Runtime) - } - - - import autoImport._ - import MOOCSettings.autoImport._ - - override lazy val projectSettings = Seq( - packageSubmissionSetting, - fork := true, - connectInput in run := true, - outputStrategy := Some(StdoutOutput), - ) ++ - packageSubmissionZipSettings ++ - inConfig(Grading)(Defaults.testSettings ++ Seq( - unmanagedJars += file("grading-tests.jar"), - - definedTests := (definedTests in Test).value, - internalDependencyClasspath := (internalDependencyClasspath in Test).value - )) - - - /** ********************************************************** - * SUBMITTING A SOLUTION TO COURSERA - */ - - val packageSubmissionZipSettings = Seq( - packageSubmissionZip := { - val submission = crossTarget.value / "submission.zip" - val sources = (packageSourcesOnly in Compile).value - val binaries = (packageBinWithoutResources in Compile).value - IO.zip(Seq(sources -> "sources.zip", binaries -> "binaries.jar"), submission, None) - submission - }, - artifactClassifier in packageSourcesOnly := Some("sources"), - artifact in (Compile, packageBinWithoutResources) ~= (art => art.withName(art.name + "-without-resources")) - ) ++ - inConfig(Compile)( - Defaults.packageTaskSettings(packageSourcesOnly, Defaults.sourceMappings) ++ - Defaults.packageTaskSettings(packageBinWithoutResources, Def.task { - val relativePaths = - (unmanagedResources in Compile).value.flatMap(Path.relativeTo((unmanagedResourceDirectories in Compile).value)(_)) - (mappings in (Compile, packageBin)).value.filterNot { case (_, path) => relativePaths.contains(path) } - }) - ) - - val maxSubmitFileSize = { - val mb = 1024 * 1024 - 10 * mb - } - - /** Check that the jar exists, isn't empty, isn't crazy big, and can be read - * If so, encode jar as base64 so we can send it to Coursera - */ - def prepareJar(jar: File, s: TaskStreams): String = { - val errPrefix = "Error submitting assignment jar: " - val fileLength = jar.length() - if (!jar.exists()) { - s.log.error(errPrefix + "jar archive does not exist\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength == 0L) { - s.log.error(errPrefix + "jar archive is empty\n" + jar.getAbsolutePath) - failSubmit() - } else if (fileLength > maxSubmitFileSize) { - s.log.error(errPrefix + "jar archive is too big. Allowed size: " + - maxSubmitFileSize + " bytes, found " + fileLength + " bytes.\n" + - jar.getAbsolutePath) - failSubmit() - } else { - val bytes = new Array[Byte](fileLength.toInt) - val sizeRead = try { - val is = new FileInputStream(jar) - val read = is.read(bytes) - is.close() - read - } catch { - case ex: IOException => - s.log.error(errPrefix + "failed to read sources jar archive\n" + ex.toString) - failSubmit() - } - if (sizeRead != bytes.length) { - s.log.error(errPrefix + "failed to read the sources jar archive, size read: " + sizeRead) - failSubmit() - } else encodeBase64(bytes) - } - } - - /** Task to package solution to a given file path */ - lazy val packageSubmissionSetting = packageSubmission := { - val args: Seq[String] = Def.spaceDelimited("[path]").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val base64Jar = prepareJar(jar, s) - - val path = args.headOption.getOrElse((baseDirectory.value / "submission.jar").absolutePath) - scala.tools.nsc.io.File(path).writeAll(base64Jar) - } - -/* - /** Task to submit a solution to coursera */ - val submit = inputKey[Unit]("submit solution to Coursera") - lazy val submitSetting = submit := { - // Fail if scalafix linting does not pass. - scalafixLinting.value - - val args: Seq[String] = Def.spaceDelimited("<arg>").parsed - val s: TaskStreams = streams.value // for logging - val jar = (packageSubmissionZip in Compile).value - - val assignmentDetails = - courseraId.?.value.getOrElse(throw new MessageOnlyException("This assignment can not be submitted to Coursera because the `courseraId` setting is undefined")) - val assignmentKey = assignmentDetails.key - val courseName = - course.value match { - case "capstone" => "scala-capstone" - case "bigdata" => "scala-spark-big-data" - case other => other - } - - val partId = assignmentDetails.partId - val itemId = assignmentDetails.itemId - val premiumItemId = assignmentDetails.premiumItemId - - val (email, secret) = args match { - case email :: secret :: Nil => - (email, secret) - case _ => - val inputErr = - s"""|Invalid input to `submit`. The required syntax for `submit` is: - |submit <email-address> <submit-token> - | - |The submit token is NOT YOUR LOGIN PASSWORD. - |It can be obtained from the assignment page: - |https://www.coursera.org/learn/$courseName/programming/$itemId - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - """.stripMargin - s.log.error(inputErr) - failSubmit() - } - - val base64Jar = prepareJar(jar, s) - val json = - s"""|{ - | "assignmentKey":"$assignmentKey", - | "submitterEmail":"$email", - | "secret":"$secret", - | "parts":{ - | "$partId":{ - | "output":"$base64Jar" - | } - | } - |}""".stripMargin - - def postSubmission[T](data: String): Try[HttpResponse[String]] = { - val http = Http("https://www.coursera.org/api/onDemandProgrammingScriptSubmissions.v1") - val hs = List( - ("Cache-Control", "no-cache"), - ("Content-Type", "application/json") - ) - s.log.info("Connecting to Coursera...") - val response = Try(http.postData(data) - .headers(hs) - .option(HttpOptions.connTimeout(10000)) // scalaj default timeout is only 100ms, changing that to 10s - .asString) // kick off HTTP POST - response - } - - val connectMsg = - s"""|Attempting to submit "${assignment.value}" assignment in "$courseName" course - |Using: - |- email: $email - |- submit token: $secret""".stripMargin - s.log.info(connectMsg) - - def reportCourseraResponse(response: HttpResponse[String]): Unit = { - val code = response.code - val respBody = response.body - - /* Sample JSON response from Coursera - { - "message": "Invalid email or token.", - "details": { - "learnerMessage": "Invalid email or token." - } - } - */ - - // Success, Coursera responds with 2xx HTTP status code - if (response.is2xx) { - val successfulSubmitMsg = - s"""|Successfully connected to Coursera. (Status $code) - | - |Assignment submitted successfully! - | - |You can see how you scored by going to: - |https://www.coursera.org/learn/$courseName/programming/$itemId/ - |${ - premiumItemId.fold("") { id => - s"""or (for premium learners): - |https://www.coursera.org/learn/$courseName/programming/$id - """.stripMargin - } - } - |and clicking on "My Submission".""".stripMargin - s.log.info(successfulSubmitMsg) - } - - // Failure, Coursera responds with 4xx HTTP status code (client-side failure) - else if (response.is4xx) { - val result = Try(Json.parse(respBody)).toOption - val learnerMsg = result match { - case Some(resp: JsObject) => - (JsPath \ "details" \ "learnerMessage").read[String].reads(resp).get - case Some(x) => // shouldn't happen - "Could not parse Coursera's response:\n" + x - case None => - "Could not parse Coursera's response:\n" + respBody - } - val failedSubmitMsg = - s"""|Submission failed. - |There was something wrong while attempting to submit. - |Coursera says: - |$learnerMsg (Status $code)""".stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera responds with 5xx HTTP status code (server-side failure) - else if (response.is5xx) { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera seems to be unavailable at the moment (Status $code) - |Check https://status.coursera.org/ and try again in a few minutes. - """.stripMargin - s.log.error(failedSubmitMsg) - } - - // Failure, Coursera repsonds with an unexpected status code - else { - val failedSubmitMsg = - s"""|Submission failed. - |Coursera replied with an unexpected code (Status $code) - """.stripMargin - s.log.error(failedSubmitMsg) - } - } - - // kick it all off, actually make request - postSubmission(json) match { - case Success(resp) => reportCourseraResponse(resp) - case Failure(e) => - val failedConnectMsg = - s"""|Connection to Coursera failed. - |There was something wrong while attempting to connect to Coursera. - |Check your internet connection. - |${e.toString}""".stripMargin - s.log.error(failedConnectMsg) - } - - } -*/ - - def failSubmit(): Nothing = { - sys.error("Submission failed") - } - - /** - * ***************** - * DEALING WITH JARS - */ - def encodeBase64(bytes: Array[Byte]): String = - new String(Base64.encodeBase64(bytes)) -} diff --git a/previous-exams/2021-midterm/m7/project/build.properties b/previous-exams/2021-midterm/m7/project/build.properties deleted file mode 100644 index 0b2e09c5ac99bd3de91b2b139b94301c2b6e26f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.4.7 diff --git a/previous-exams/2021-midterm/m7/project/buildSettings.sbt b/previous-exams/2021-midterm/m7/project/buildSettings.sbt deleted file mode 100644 index 8fac702aaf3f3c4ede79691c7b4e4a52f26f3f47..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/buildSettings.sbt +++ /dev/null @@ -1,5 +0,0 @@ -// Used for Coursera submission (StudentPlugin) -// libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2" -// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.7.4" -// Used for Base64 (StudentPlugin) -libraryDependencies += "commons-codec" % "commons-codec" % "1.10" diff --git a/previous-exams/2021-midterm/m7/project/plugins.sbt b/previous-exams/2021-midterm/m7/project/plugins.sbt deleted file mode 100644 index fb7dbe068109e7f35c13b2762b865c7eec1979f3..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/project/plugins.sbt +++ /dev/null @@ -1,3 +0,0 @@ -// addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.28") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8") -addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.5.3") diff --git a/previous-exams/2021-midterm/m7/src/main/scala/m7/M7.scala b/previous-exams/2021-midterm/m7/src/main/scala/m7/M7.scala deleted file mode 100644 index 20afd03b796e95251fa3c92993066c7bebfe6ea8..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/src/main/scala/m7/M7.scala +++ /dev/null @@ -1,69 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait M7 extends Lib { - - class DLLCombinerImplementation(chunk_size: Int = 3) extends DLLCombiner(chunk_size){ - - // Computes every other Integer element of data array, starting from the second, up to the middle - def task1(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the first (index 0), up to the middle - def task2(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the last, up to the middle - def task3(data: Array[Int]): ForkJoinTask[Unit] = task { - ??? - } - - // Computes every other Integer element of data array, starting from the second to last, up to the middle - // This is executed on the current thread. - def task4(data: Array[Int]): Unit = { - ??? - } - - def result(): Array[Int] = { - val data = new Array[Int](cnt) - - ??? - - data - } - - private def copyForward(data: Array[Int], curr: Node, from: Int, to: Int, limit: Int) = { - var current = curr - var i_from = from - var i_to = to - - while (i_to < limit) { - try { - data(i_to) = current.value(i_from) - i_to += 2 - i_from += 2 - if(i_from == current.cnt){ - current = current.next - i_from = 0 - } - else if(i_from > current.cnt) { - current = current.next - i_from = 1 - if(current.cnt == 1) { - current = current.next - i_from = 0 - } - } - } - catch{ - case e: Exception => - } - } - } - } - -} diff --git a/previous-exams/2021-midterm/m7/src/main/scala/m7/lib.scala b/previous-exams/2021-midterm/m7/src/main/scala/m7/lib.scala deleted file mode 100644 index 20eda60c5fe1bae1271615650af917ff08929690..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/src/main/scala/m7/lib.scala +++ /dev/null @@ -1,84 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -trait Lib { - - class Node(val size: Int) { - var value: Array[Int] = new Array(size) - var next: Node = null - var previous: Node = null - var cnt = 0 - - def add(v: Int) = { - value(cnt) = v - cnt += 1 - } - } - - // Simplified Combiner interface - // Implements methods += and combine - // Abstract methods should be implemented in subclasses - abstract class DLLCombiner(val chunk_size: Int) { - var head: Node = null - var last: Node = null - var cnt: Int = 0 - var chunks: Int = 0 - - // Adds an Integer to the last node of this array combiner. If the last node is full, allocates a new node. - def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - // Combines this array combiner and another given combiner in constant O(1) complexity. - def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - - def task1(data: Array[Int]): ForkJoinTask[Unit] - def task2(data: Array[Int]): ForkJoinTask[Unit] - def task3(data: Array[Int]): ForkJoinTask[Unit] - def task4(data: Array[Int]): Unit - - def result(): Array[Int] - - } - - def task[T](body: => T): ForkJoinTask[T] - -} \ No newline at end of file diff --git a/previous-exams/2021-midterm/m7/src/test/scala/m7/M7Suite.scala b/previous-exams/2021-midterm/m7/src/test/scala/m7/M7Suite.scala deleted file mode 100644 index 8e1c344eacca6b10c5646a7318fb1c0c19252bc5..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm/m7/src/test/scala/m7/M7Suite.scala +++ /dev/null @@ -1,422 +0,0 @@ -package m7 - -import java.util.concurrent._ -import scala.util.DynamicVariable - -class M7Suite extends AbstractM7Suite { - - // (70+) 30 / 500 points for correct implementation, don't check parallelism - test("[Correctness] fetch result - simple combiners (5pts)") { - assertCorrectnessSimple() - } - - test("[Correctness] fetch result - small combiners (5pts)") { - assertCorrectnessBasic() - } - - test("[Correctness] fetch result - small combiners after combining (10pts)") { - assertCorrectnessCombined() - } - - test("[Correctness] fetch result - large combiners (10pts)") { - assertCorrectnessLarge() - } - - def assertCorrectnessSimple() = { - simpleCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessBasic() = { - basicCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessCombined() = { - combinedCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - def assertCorrectnessLarge() = { - largeCombiners.foreach(elem => assert(compare(elem._1, elem._2))) - } - - // (70+30+) 50 / 500 points for correct parallel implementation, don't check if it's exactly 1/4 of the array per task - private var count = 0 - private val expected = 3 - - override def task[T](body: => T): ForkJoinTask[T] = { - count += 1 - scheduler.value.schedule(body) - } - - test("[TaskCount] number of newly created tasks should be 3 (5pts)") { - assertTaskCountSimple() - } - - test("[TaskCount] fetch result and check parallel - simple combiners (5pts)") { - assertTaskCountSimple() - assertCorrectnessSimple() - } - - test("[TaskCount] fetch result and check parallel - small combiners (10pts)") { - assertTaskCountSimple() - assertCorrectnessBasic() - } - - test("[TaskCount] fetch result and check parallel - small combiners after combining (15pts)") { - assertTaskCountSimple() - assertCorrectnessCombined() - } - - test("[TaskCount] fetch result and check parallel - large combiners (15pts)") { - assertTaskCountSimple() - assertCorrectnessLarge() - } - - def assertTaskCountSimple(): Unit = { - simpleCombiners.foreach(elem => assertTaskCount(elem._1, elem._2)) - } - - def assertTaskCount(combiner: DLLCombinerTest, array: Array[Int]): Unit = { - try { - count = 0 - build(combiner, array) - combiner.result() - assertEquals(count, expected, { - s"ERROR: Expected $expected instead of $count calls to `task(...)`" - }) - } finally { - count = 0 - } - } - - //(70+30+50+) 200 / 500 points for correct parallel implementation, exactly 1/4 of the array per task - test("[TaskFairness] each task should compute 1/4 of the result (50pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - simple combiners (20pts)") { - assertTaskFairness(simpleCombiners.unzip._1) - assertCorrectnessSimple() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners (30pts)") { - assertTaskFairness(basicCombiners.unzip._1) - assertCorrectnessBasic() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - small combiners after combining (50pts)") { - assertTaskFairness(combinedCombiners.unzip._1) - assertCorrectnessCombined() - } - - test("[TaskFairness] each task should correctly compute 1/4 of the result - large combiners (50pts)") { - assertTaskFairness(largeCombiners.unzip._1) - assertCorrectnessLarge() - } - - def assertTaskFairness(combiners: List[DLLCombinerTest]): Unit = { - def assertNewTaskFairness(combiner: DLLCombinerTest, task: ForkJoinTask[Unit], data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - task.join - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - def assertMainTaskFairness(combiner: DLLCombinerTest, task: Unit, data: Array[Int]) = { - var count = 0 - var expected = combiner.cnt / 4 - count = data.count(elem => elem != 0) - - assert((count - expected).abs <= 1) - } - - combiners.foreach { elem => - var data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task1(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task2(data), data) - - data = Array.fill(elem.cnt)(0) - assertNewTaskFairness(elem, elem.task3(data), data) - - data = Array.fill(elem.cnt)(0) - assertMainTaskFairness(elem, elem.task4(data), data) - } - } - - //(70+30+50+200+) 150 / 500 points for correct parallel implementation, exactly 1/4 of the array per task, exactly the specified quarter - - test("[TaskPrecision] each task should compute specified 1/4 of the result - simple combiners (20pts)") { - assertTaskPrecision(simpleCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners (30pts)") { - assertTaskPrecision(basicCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - small combiners after combining (50pts)") { - assertTaskPrecision(combinedCombiners) - } - - test("[TaskPrecision] each task should compute specified 1/4 of the result - large combiners (50pts)") { - assertTaskPrecision(largeCombiners) - } - - def assertTaskPrecision(combiners: List[(DLLCombinerTest, Array[Int])]): Unit = { - combiners.foreach { elem => - var data = Array.fill(elem._1.cnt)(0) - var ref = Array.fill(elem._1.cnt)(0) - val task1 = elem._1.task1(data) - task1.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 1) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task2 = elem._1.task2(data) - task2.join - Range(0, elem._1.cnt).foreach(i => (if (i < elem._1.cnt / 2 - 1 && i % 2 == 0) ref(i) = elem._2(i))) - assert(Range(0, elem._1.cnt / 2 - 1).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task3 = elem._1.task3(data) - task3.join - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 != elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - - data = Array.fill(elem._1.cnt)(0) - ref = Array.fill(elem._1.cnt)(0) - val task4 = elem._1.task4(data) - Range(0, elem._1.cnt).foreach(i => (if (i > elem._1.cnt / 2 + 1 && i % 2 == elem._1.cnt % 2) ref(i) = elem._2(i))) - assert(Range(elem._1.cnt / 2 + 2, elem._1.cnt).forall(i => data(i) == ref(i))) - } - } - - test("[Public] fetch simple result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1, 2, 3, 8) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result without combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - combiner1 += 3 - combiner1 += 8 - combiner1 += 1 - - val result = combiner1.result() - val array = Array(7, 2, 3, 8, 1) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result after simple combining (5pts)") { - val combiner1 = DLLCombinerTest(2) - combiner1 += 7 - combiner1 += 2 - - val combiner2 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 8 - - val combiner3 = DLLCombinerTest(2) - combiner2 += 1 - combiner2 += 9 - - val combiner4 = DLLCombinerTest(2) - combiner2 += 3 - combiner2 += 2 - - val result = combiner1.combine(combiner2).combine(combiner3).combine(combiner4).result() - val array = Array(7, 2, 3, 8, 1, 9, 3, 2) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - - test("[Public] fetch result - empty combiner (20pts)") { - val combiner1 = DLLCombinerTest(2) - val result = combiner1.result() - assertEquals(result.size, 0) - } - - test("[Public] fetch result - full single element combiner (15pts)") { - val combiner1 = DLLCombinerTest(3) - combiner1 += 4 - combiner1 += 2 - combiner1 += 6 - - val result = combiner1.result() - val array = Array(4, 2, 6) - - assert(Range(0,array.size).forall(i => array(i) == result(i))) - } - -} - - -trait AbstractM7Suite extends munit.FunSuite with LibImpl { - - def simpleCombiners = buildSimpleCombiners() - def basicCombiners = buildBasicCombiners() - def combinedCombiners = buildCombinedCombiners() - def largeCombiners = buildLargeCombiners() - - def buildSimpleCombiners() = { - val simpleCombiners = List( - (DLLCombinerTest(4), Array(4, 2, 6, 1, 5, 4, 3, 5, 6, 3, 4, 5, 6, 3, 4, 5)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2)), - (DLLCombinerTest(4), Array.fill(16)(5)) - ) - simpleCombiners.foreach(elem => build(elem._1, elem._2)) - simpleCombiners - } - - def buildBasicCombiners() = { - val basicCombiners = List( - (DLLCombinerTest(2), Array(4, 2, 6)), - (DLLCombinerTest(5), Array(4, 2, 6)), - (DLLCombinerTest(3), Array(4, 2, 6, 1, 7, 2, 4)), - (DLLCombinerTest(4), Array(7, 2, 2, 9, 3, 2, 11, 12, 13, 14, 15, 16, 17, 22)), - (DLLCombinerTest(3), Array.fill(16)(7)), - (DLLCombinerTest(3), Array.fill(19)(7)), - (DLLCombinerTest(3), Array.fill(5)(7)), - (DLLCombinerTest(3), Array.fill(6)(7)) - ) - basicCombiners.foreach(elem => build(elem._1, elem._2)) - basicCombiners - } - - def buildCombinedCombiners() = { - var combinedCombiners = List[(DLLCombinerTest, Array[Int])]() - Range(1, 10).foreach { chunk_size => - val array = basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foldLeft(Array[Int]()) { (acc, i) => acc ++ i._2 } - val combiner = DLLCombinerTest(chunk_size) - basicCombiners.filter(elem => elem._1.chunk_size == chunk_size).foreach(elem => combiner.combine(elem._1)) - - combinedCombiners = combinedCombiners :+ (combiner, array) - } - combinedCombiners - } - - def buildLargeCombiners() = { - val largeCombiners = List( - (DLLCombinerTest(21), Array.fill(1321)(4) ++ Array.fill(1322)(7)), - (DLLCombinerTest(18), Array.fill(1341)(2) ++ Array.fill(1122)(5)), - (DLLCombinerTest(3), Array.fill(1321)(4) ++ Array.fill(1322)(7) ++ Array.fill(321)(4) ++ Array.fill(322)(7)), - (DLLCombinerTest(12), Array.fill(992321)(4) ++ Array.fill(99322)(7)), - (DLLCombinerTest(4), Array.fill(953211)(4) ++ Array.fill(999322)(1)) - ) - largeCombiners.foreach(elem => build(elem._1, elem._2)) - largeCombiners - } - - def build(combiner: DLLCombinerTest, array: Array[Int]): DLLCombinerTest = { - array.foreach(elem => combiner += elem) - combiner - } - - def compare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - val result = combiner.result() - Range(0,array.size).forall(i => array(i) == result(i)) - } - - def buildAndCompare(combiner: DLLCombinerTest, array: Array[Int]): Boolean = { - array.foreach(elem => combiner += elem) - val result = combiner.result() - - Range(0,array.size).forall(i => array(i) == result(i)) - } - -} - -trait LibImpl extends M7 { - - val forkJoinPool = new ForkJoinPool - - abstract class TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] - } - - class DefaultTaskScheduler extends TaskScheduler { - def schedule[T](body: => T): ForkJoinTask[T] = { - val t = new RecursiveTask[T] { - def compute = body - } - Thread.currentThread match { - case wt: ForkJoinWorkerThread => - t.fork() - case _ => - forkJoinPool.execute(t) - } - t - } - } - - val scheduler = - new DynamicVariable[TaskScheduler](new DefaultTaskScheduler) - - def task[T](body: => T): ForkJoinTask[T] = { - scheduler.value.schedule(body) - } - - class DLLCombinerTest(chunk_size: Int = 3) extends DLLCombinerImplementation(chunk_size) { - - override def +=(elem: Int): Unit = { - if(cnt % chunk_size == 0) { - chunks = chunks + 1 - val node = new Node(chunk_size) - if (cnt == 0) { - head = node - last = node - } - else { - last.next = node - node.previous = last - last = node - } - } - last.add(elem) - cnt += 1 - } - - override def combine(that: DLLCombiner): DLLCombiner = { - assert(this.chunk_size == that.chunk_size) - if (this.cnt == 0) { - this.head = that.head - this.last = that.last - this.cnt = that.cnt - this.chunks = that.chunks - - this - } - else if (that.cnt == 0) - this - else { - this.last.next = that.head - that.head.previous = this.last - - this.cnt = this.cnt + that.cnt - this.chunks = this.chunks + that.chunks - this.last = that.last - - this - } - } - } -} diff --git a/previous-exams/2022-midterm-code/.gitignore b/previous-exams/2022-midterm-code/.gitignore deleted file mode 100644 index 99dff8673c4ef8df812216a88ec4901f582bac02..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.vscode -.metals -.bloop -.bsp -target -metals.sbt -build.properties diff --git a/previous-exams/2022-midterm-code/.scalafmt.conf b/previous-exams/2022-midterm-code/.scalafmt.conf deleted file mode 100644 index 1cea5243def8047a81295a8b13cb970660e0b3fc..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/.scalafmt.conf +++ /dev/null @@ -1,4 +0,0 @@ -version = "3.4.0" -runner.dialect = scala3 -rewrite.scala3.convertToNewSyntax = true -rewrite.scala3.removeOptionalBraces = true diff --git a/previous-exams/2022-midterm-code/Readme.md b/previous-exams/2022-midterm-code/Readme.md deleted file mode 100644 index c34af5a8e23596db04aca38ae0f71a03cbd6eb03..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/Readme.md +++ /dev/null @@ -1,41 +0,0 @@ -# How to run - -This folder contains the code of most of the exercises of the midterm, along with tests and comments. - -- Questions 1-3: [Part1.scala](src/main/scala/midterm/Part1.scala) and [Part1Test.scala](src/test/scala/midterm/Part1Test.scala) -- Questions 4-7: [Part2.scala](src/main/scala/midterm/Part2.scala) and [Part2Test.scala](src/test/scala/midterm/Part2Test.scala) -- Question 8: [Part3.scala](src/main/scala/midterm/Part3.scala) -- Questions 9-15: [Part4.scala](src/main/scala/midterm/Part4.scala) and [Part4Test.scala](src/test/scala/midterm/Part4Test.scala) -- Question 21: [Part6.scala](src/main/scala/midterm/Part6.scala) and [Part6Test.scala](src/test/scala/midterm/Part6Test.scala) -- Questions 22-24: [Part7.scala](src/main/scala/midterm/Part7.scala) and [Part7Test.scala](src/test/scala/midterm/Part7Test.scala) -- Question 25: [Part8.scala](src/main/scala/midterm/Part8.scala) and [Part8Test.scala](src/test/scala/midterm/Part8Test.scala) - -## Test - -``` -sbt test -``` - -or to run a specific suite: - -``` -sbt "testOnly midterm.Part1Test" -``` - -## Run a main function - -``` -sbt "runMain midterm.part3" -``` - -## Format - -``` -sbt scalafmt -``` - -## Benchmark - -``` -sbt "jmh:run -bm ss -i 40 -wi 5 -rf JSON -rff CollectionsBenchmarkResults.json bench.CollectionBenchmark" -``` diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.json b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.json deleted file mode 100644 index 36b3ee32a5224806fabecdaf9b9791fc184dd3d0..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.json +++ /dev/null @@ -1,8260 +0,0 @@ -[ - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.3138780000000006E-5, - "scoreError" : 1.528127842192391E-6, - "scoreConfidence" : [ - 1.1610652157807614E-5, - 1.4666907842192397E-5 - ], - "scorePercentiles" : { - "0.0" : 6.417E-6, - "50.0" : 1.0846499999999999E-5, - "90.0" : 2.1913700000000007E-5, - "95.0" : 3.0361999999999964E-5, - "99.0" : 3.877779000000002E-5, - "99.9" : 4.271E-5, - "99.99" : 4.271E-5, - "99.999" : 4.271E-5, - "99.9999" : 4.271E-5, - "100.0" : 4.271E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.0306E-5, - 9.856E-6, - 9.549E-6, - 9.725E-6, - 8.996E-6, - 9.291E-6, - 9.531E-6, - 9.606E-6, - 1.0886E-5, - 1.1025E-5, - 1.0233E-5, - 1.0611E-5, - 1.452E-5, - 1.0263E-5, - 1.4691E-5, - 1.075E-5, - 1.4091E-5, - 1.3805E-5, - 9.645E-6, - 1.3027E-5, - 1.5055E-5, - 9.623E-6, - 1.0055E-5, - 9.553E-6, - 9.76E-6, - 8.182E-6, - 7.954E-6, - 9.106E-6, - 1.0187E-5, - 8.079E-6, - 8.994E-6, - 8.199E-6, - 8.628E-6, - 1.0725E-5, - 9.59E-6, - 8.075E-6, - 1.2181E-5, - 4.271E-5, - 9.506E-6, - 1.4042E-5 - ], - [ - 1.433E-5, - 1.4074E-5, - 1.5759E-5, - 1.1535E-5, - 1.0959E-5, - 1.4021E-5, - 1.452E-5, - 1.6772E-5, - 1.0264E-5, - 1.4797E-5, - 1.075E-5, - 1.6043E-5, - 2.7417E-5, - 1.5585E-5, - 3.0517E-5, - 1.1777E-5, - 1.1615E-5, - 3.1193E-5, - 3.3444E-5, - 1.2913E-5, - 1.5243E-5, - 3.7173E-5, - 9.412E-6, - 1.0145E-5, - 3.6325E-5, - 7.672E-6, - 7.176E-6, - 9.216E-6, - 3.4192E-5, - 1.3987E-5, - 2.2034E-5, - 7.566E-6, - 7.717E-6, - 1.0716E-5, - 1.0879E-5, - 2.2625E-5, - 1.2431E-5, - 2.0191E-5, - 1.133E-5, - 1.108E-5 - ], - [ - 1.8399E-5, - 1.8937E-5, - 2.0831E-5, - 1.863E-5, - 1.2124E-5, - 1.6012E-5, - 1.4496E-5, - 1.359E-5, - 1.2414E-5, - 1.3463E-5, - 1.3907E-5, - 1.7746E-5, - 1.6589E-5, - 1.1352E-5, - 1.1967E-5, - 1.1069E-5, - 1.5535E-5, - 2.7037E-5, - 1.3044E-5, - 1.2464E-5, - 2.454E-5, - 1.1621E-5, - 1.6172E-5, - 1.2906E-5, - 1.3601E-5, - 2.2422E-5, - 1.1522E-5, - 1.2671E-5, - 1.7785E-5, - 1.3904E-5, - 1.422E-5, - 1.4986E-5, - 1.4666E-5, - 1.4135E-5, - 1.2964E-5, - 1.5253E-5, - 1.4946E-5, - 2.3892E-5, - 1.3321E-5, - 1.2976E-5 - ], - [ - 1.0836E-5, - 9.783E-6, - 9.625E-6, - 9.758E-6, - 9.362E-6, - 9.159E-6, - 1.0604E-5, - 9.923E-6, - 9.577E-6, - 8.597E-6, - 9.215E-6, - 1.0216E-5, - 3.239E-5, - 1.0253E-5, - 1.062E-5, - 1.0587E-5, - 1.0857E-5, - 1.1998E-5, - 2.3706E-5, - 9.751E-6, - 1.5493E-5, - 9.656E-6, - 9.869E-6, - 2.5335E-5, - 8.625E-6, - 7.898E-6, - 2.2052E-5, - 3.5788E-5, - 9.673E-6, - 8.262E-6, - 8.042E-6, - 7.949E-6, - 7.327E-6, - 6.783E-6, - 6.417E-6, - 7.957E-6, - 8.223E-6, - 1.261E-5, - 7.431E-6, - 8.913E-6 - ], - [ - 1.181E-5, - 1.0401E-5, - 9.595E-6, - 1.0438E-5, - 9.703E-6, - 9.85E-6, - 1.1082E-5, - 1.0794E-5, - 1.1058E-5, - 1.1085E-5, - 1.018E-5, - 1.008E-5, - 1.0231E-5, - 9.602E-6, - 9.811E-6, - 9.628E-6, - 1.082E-5, - 1.139E-5, - 3.8794E-5, - 9.979E-6, - 1.7579E-5, - 1.3581E-5, - 1.0044E-5, - 9.086E-6, - 8.007E-6, - 7.865E-6, - 7.832E-6, - 7.794E-6, - 7.127E-6, - 1.1444E-5, - 1.0192E-5, - 8.82E-6, - 7.868E-6, - 7.727E-6, - 1.0464E-5, - 9.907E-6, - 9.264E-6, - 1.4598E-5, - 8.577E-6, - 8.414E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.1416414999999992E-5, - "scoreError" : 1.014676800120889E-6, - "scoreConfidence" : [ - 1.0401738199879103E-5, - 1.2431091800120882E-5 - ], - "scorePercentiles" : { - "0.0" : 6.331E-6, - "50.0" : 1.04425E-5, - "90.0" : 1.61839E-5, - "95.0" : 1.8340299999999998E-5, - "99.0" : 3.658052000000006E-5, - "99.9" : 4.0758E-5, - "99.99" : 4.0758E-5, - "99.999" : 4.0758E-5, - "99.9999" : 4.0758E-5, - "100.0" : 4.0758E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.6654E-5, - 1.3017E-5, - 1.1719E-5, - 1.1473E-5, - 1.2789E-5, - 1.7562E-5, - 1.1402E-5, - 1.0957E-5, - 1.1022E-5, - 1.0857E-5, - 1.9211E-5, - 1.0053E-5, - 8.794E-6, - 1.4189E-5, - 8.799E-6, - 8.428E-6, - 8.875E-6, - 1.5506E-5, - 1.2279E-5, - 1.0776E-5, - 1.0253E-5, - 1.0816E-5, - 9.789E-6, - 8.917E-6, - 9.142E-6, - 1.0466E-5, - 9.732E-6, - 9.131E-6, - 9.337E-6, - 9.131E-6, - 9.259E-6, - 2.0806E-5, - 9.287E-6, - 1.297E-5, - 1.6724E-5, - 6.561E-6, - 6.727E-6, - 1.3086E-5, - 7.039E-6, - 6.768E-6 - ], - [ - 1.3694E-5, - 1.2035E-5, - 1.2569E-5, - 1.1748E-5, - 1.1688E-5, - 1.8348E-5, - 1.0778E-5, - 1.0423E-5, - 1.0763E-5, - 1.0834E-5, - 1.87E-5, - 1.0053E-5, - 9.602E-6, - 1.6502E-5, - 1.006E-5, - 1.0053E-5, - 1.0125E-5, - 1.9536E-5, - 1.1442E-5, - 1.434E-5, - 1.0998E-5, - 1.1131E-5, - 1.0462E-5, - 1.0604E-5, - 9.104E-6, - 9.271E-6, - 9.19E-6, - 8.833E-6, - 8.281E-6, - 8.246E-6, - 8.847E-6, - 1.5516E-5, - 9.373E-6, - 1.3942E-5, - 8.46E-6, - 1.5949E-5, - 6.548E-6, - 1.1795E-5, - 7.333E-6, - 6.785E-6 - ], - [ - 1.5676E-5, - 1.1669E-5, - 1.1585E-5, - 1.0984E-5, - 1.1836E-5, - 1.6963E-5, - 1.1479E-5, - 1.1389E-5, - 1.0249E-5, - 1.0889E-5, - 1.919E-5, - 9.701E-6, - 8.523E-6, - 1.5889E-5, - 8.579E-6, - 9.033E-6, - 8.968E-6, - 1.621E-5, - 1.2278E-5, - 1.2375E-5, - 1.3013E-5, - 1.3077E-5, - 1.097E-5, - 9.595E-6, - 8.89E-6, - 1.0333E-5, - 9.281E-6, - 8.809E-6, - 8.543E-6, - 8.466E-6, - 8.679E-6, - 3.6649E-5, - 8.804E-6, - 1.3674E-5, - 8.851E-6, - 1.7827E-5, - 6.865E-6, - 1.1414E-5, - 7.07E-6, - 6.331E-6 - ], - [ - 1.3575E-5, - 1.2263E-5, - 1.2486E-5, - 1.1627E-5, - 1.1402E-5, - 1.8194E-5, - 1.1049E-5, - 1.2736E-5, - 1.0321E-5, - 1.0403E-5, - 1.9206E-5, - 1.1677E-5, - 8.518E-6, - 1.4557E-5, - 8.344E-6, - 1.0052E-5, - 8.284E-6, - 2.9801E-5, - 1.3209E-5, - 1.0858E-5, - 1.187E-5, - 1.21E-5, - 9.484E-6, - 1.0836E-5, - 8.927E-6, - 8.457E-6, - 8.169E-6, - 8.153E-6, - 8.491E-6, - 8.244E-6, - 9.443E-6, - 4.0758E-5, - 9.821E-6, - 1.5875E-5, - 7.868E-6, - 1.5702E-5, - 7.29E-6, - 1.1847E-5, - 6.395E-6, - 6.682E-6 - ], - [ - 1.4617E-5, - 1.1494E-5, - 1.2513E-5, - 1.2272E-5, - 1.2321E-5, - 1.1178E-5, - 1.053E-5, - 9.885E-6, - 9.174E-6, - 8.963E-6, - 9.52E-6, - 9.518E-6, - 9.188E-6, - 1.5553E-5, - 8.849E-6, - 9.332E-6, - 8.904E-6, - 1.483E-5, - 1.3121E-5, - 1.0955E-5, - 1.0317E-5, - 9.472E-6, - 9.188E-6, - 9.114E-6, - 9.825E-6, - 8.84E-6, - 9.089E-6, - 8.939E-6, - 8.698E-6, - 8.959E-6, - 8.458E-6, - 1.753E-5, - 8.547E-6, - 1.4813E-5, - 1.6901E-5, - 6.454E-6, - 8.099E-6, - 1.2578E-5, - 7.504E-6, - 7.397E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 1.7079950000000002E-5, - "scoreError" : 1.533958144309828E-6, - "scoreConfidence" : [ - 1.5545991855690175E-5, - 1.861390814430983E-5 - ], - "scorePercentiles" : { - "0.0" : 8.727E-6, - "50.0" : 1.6804E-5, - "90.0" : 2.2987900000000004E-5, - "95.0" : 2.7795449999999978E-5, - "99.0" : 4.326946000000005E-5, - "99.9" : 6.49E-5, - "99.99" : 6.49E-5, - "99.999" : 6.49E-5, - "99.9999" : 6.49E-5, - "100.0" : 6.49E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.865E-5, - 1.4176E-5, - 1.2085E-5, - 1.985E-5, - 1.8564E-5, - 2.0125E-5, - 1.7305E-5, - 1.2902E-5, - 1.2124E-5, - 1.2728E-5, - 2.1187E-5, - 1.712E-5, - 2.0204E-5, - 2.3808E-5, - 1.2106E-5, - 9.674E-6, - 1.3812E-5, - 1.1189E-5, - 1.078E-5, - 1.6107E-5, - 1.6141E-5, - 1.634E-5, - 1.6702E-5, - 1.7796E-5, - 2.8103E-5, - 1.7964E-5, - 1.8142E-5, - 1.8601E-5, - 1.8233E-5, - 1.2647E-5, - 1.0267E-5, - 2.8344E-5, - 6.49E-5, - 1.0525E-5, - 1.0465E-5, - 1.7655E-5, - 2.4205E-5, - 3.0908E-5, - 1.2201E-5, - 1.9579E-5 - ], - [ - 1.8915E-5, - 1.9728E-5, - 2.7886E-5, - 1.681E-5, - 2.2082E-5, - 1.9644E-5, - 1.7536E-5, - 1.3776E-5, - 1.5386E-5, - 1.2743E-5, - 3.3006E-5, - 1.8311E-5, - 1.5069E-5, - 2.3226E-5, - 1.099E-5, - 1.0257E-5, - 1.8135E-5, - 1.1136E-5, - 1.3838E-5, - 1.9804E-5, - 1.4276E-5, - 1.7409E-5, - 1.7645E-5, - 1.9279E-5, - 2.171E-5, - 1.9192E-5, - 1.7333E-5, - 1.7551E-5, - 1.8161E-5, - 1.2162E-5, - 9.588E-6, - 1.8601E-5, - 2.1937E-5, - 1.0501E-5, - 1.0836E-5, - 1.9379E-5, - 1.5538E-5, - 2.0169E-5, - 1.1876E-5, - 2.2114E-5 - ], - [ - 2.0445E-5, - 1.4899E-5, - 1.8062E-5, - 2.1044E-5, - 1.9048E-5, - 1.9583E-5, - 1.6992E-5, - 1.2378E-5, - 1.2473E-5, - 1.3341E-5, - 2.0901E-5, - 1.5406E-5, - 1.869E-5, - 2.2447E-5, - 1.096E-5, - 9.352E-6, - 1.3414E-5, - 1.0932E-5, - 1.0431E-5, - 1.5892E-5, - 1.6572E-5, - 1.6655E-5, - 1.9955E-5, - 1.5727E-5, - 2.6068E-5, - 1.8046E-5, - 1.8818E-5, - 1.6798E-5, - 1.1591E-5, - 1.1544E-5, - 1.0005E-5, - 1.8357E-5, - 1.6075E-5, - 9.906E-6, - 8.727E-6, - 1.7084E-5, - 3.7672E-5, - 2.6075E-5, - 1.0989E-5, - 1.8849E-5 - ], - [ - 2.4467E-5, - 1.9172E-5, - 1.3165E-5, - 1.1442E-5, - 1.7395E-5, - 1.8077E-5, - 1.8158E-5, - 1.448E-5, - 1.293E-5, - 1.8391E-5, - 3.4903E-5, - 1.1582E-5, - 1.0108E-5, - 2.0751E-5, - 1.1295E-5, - 9.838E-6, - 1.5063E-5, - 1.5686E-5, - 1.5577E-5, - 1.328E-5, - 1.1568E-5, - 1.4959E-5, - 2.145E-5, - 1.65E-5, - 1.9852E-5, - 1.9204E-5, - 2.5608E-5, - 1.9705E-5, - 1.2544E-5, - 1.3588E-5, - 1.2074E-5, - 4.3326E-5, - 3.7287E-5, - 1.4171E-5, - 1.0878E-5, - 1.0789E-5, - 1.2042E-5, - 2.0437E-5, - 8.902E-6, - 1.9202E-5 - ], - [ - 2.0716E-5, - 1.3362E-5, - 1.316E-5, - 2.1045E-5, - 1.7549E-5, - 2.3048E-5, - 1.9364E-5, - 1.4374E-5, - 1.9262E-5, - 1.7986E-5, - 2.1837E-5, - 1.0662E-5, - 9.555E-6, - 2.3244E-5, - 9.565E-6, - 9.179E-6, - 1.5604E-5, - 1.1877E-5, - 1.0271E-5, - 9.376E-6, - 1.7637E-5, - 1.6278E-5, - 1.5403E-5, - 1.7018E-5, - 2.383E-5, - 1.8466E-5, - 2.1881E-5, - 1.5502E-5, - 1.5892E-5, - 1.6405E-5, - 1.0665E-5, - 2.0993E-5, - 1.7465E-5, - 1.7627E-5, - 1.5455E-5, - 1.1864E-5, - 9.329E-6, - 2.104E-5, - 1.354E-5, - 1.8866E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 2.3917775000000005E-5, - "scoreError" : 2.491666467469601E-6, - "scoreConfidence" : [ - 2.1426108532530403E-5, - 2.6409441467469607E-5 - ], - "scorePercentiles" : { - "0.0" : 1.1722E-5, - "50.0" : 1.97965E-5, - "90.0" : 3.643310000000001E-5, - "95.0" : 4.9687699999999995E-5, - "99.0" : 6.900151000000005E-5, - "99.9" : 7.0315E-5, - "99.99" : 7.0315E-5, - "99.999" : 7.0315E-5, - "99.9999" : 7.0315E-5, - "100.0" : 7.0315E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.0593E-5, - 1.8681E-5, - 5.6965E-5, - 1.5403E-5, - 1.7759E-5, - 1.7654E-5, - 1.5704E-5, - 2.146E-5, - 4.0335E-5, - 1.7464E-5, - 2.6358E-5, - 1.3725E-5, - 1.7096E-5, - 1.3922E-5, - 1.8184E-5, - 2.261E-5, - 1.8253E-5, - 3.3349E-5, - 2.5654E-5, - 1.7554E-5, - 2.185E-5, - 1.7867E-5, - 1.2473E-5, - 4.9703E-5, - 1.9212E-5, - 2.717E-5, - 3.1677E-5, - 1.3409E-5, - 1.7809E-5, - 1.7148E-5, - 1.7418E-5, - 1.4257E-5, - 2.1667E-5, - 1.7816E-5, - 2.0151E-5, - 1.7644E-5, - 2.2059E-5, - 3.2066E-5, - 1.1722E-5, - 7.0315E-5 - ], - [ - 2.1382E-5, - 1.9227E-5, - 3.6581E-5, - 1.8911E-5, - 1.894E-5, - 2.7913E-5, - 1.9728E-5, - 2.3467E-5, - 1.7583E-5, - 2.0011E-5, - 2.6784E-5, - 1.3342E-5, - 5.0709E-5, - 1.7694E-5, - 1.4105E-5, - 1.7017E-5, - 1.4893E-5, - 1.7828E-5, - 1.4153E-5, - 2.5573E-5, - 1.8265E-5, - 1.3049E-5, - 1.7475E-5, - 4.5301E-5, - 3.1149E-5, - 2.5455E-5, - 3.458E-5, - 1.756E-5, - 2.097E-5, - 3.1833E-5, - 1.9236E-5, - 1.8219E-5, - 2.1735E-5, - 2.4847E-5, - 1.7501E-5, - 1.7259E-5, - 1.7074E-5, - 4.8644E-5, - 1.8588E-5, - 5.6464E-5 - ], - [ - 2.1407E-5, - 1.9064E-5, - 1.9948E-5, - 2.0065E-5, - 2.4212E-5, - 1.9004E-5, - 1.9788E-5, - 2.5098E-5, - 1.7104E-5, - 2.1445E-5, - 2.6279E-5, - 1.9397E-5, - 1.8535E-5, - 1.8057E-5, - 2.664E-5, - 1.8779E-5, - 2.0885E-5, - 1.8154E-5, - 1.3421E-5, - 1.928E-5, - 1.7229E-5, - 2.5607E-5, - 1.8135E-5, - 4.6308E-5, - 3.1053E-5, - 1.5233E-5, - 4.0409E-5, - 2.0336E-5, - 2.0828E-5, - 1.7164E-5, - 2.105E-5, - 1.7019E-5, - 4.2102E-5, - 1.776E-5, - 6.2518E-5, - 1.8331E-5, - 1.908E-5, - 6.9067E-5, - 1.7986E-5, - 5.1456E-5 - ], - [ - 2.0053E-5, - 1.8458E-5, - 5.8445E-5, - 2.1644E-5, - 1.9418E-5, - 1.9302E-5, - 2.2805E-5, - 1.9617E-5, - 1.9696E-5, - 2.4858E-5, - 2.7035E-5, - 2.5537E-5, - 1.9186E-5, - 2.968E-5, - 1.6965E-5, - 2.5135E-5, - 1.8229E-5, - 2.5491E-5, - 2.15E-5, - 1.91E-5, - 2.4663E-5, - 1.7372E-5, - 1.8933E-5, - 3.1951E-5, - 4.3288E-5, - 1.8748E-5, - 3.4067E-5, - 1.6063E-5, - 1.7276E-5, - 1.9508E-5, - 5.0394E-5, - 1.924E-5, - 1.8309E-5, - 2.1459E-5, - 2.4065E-5, - 1.724E-5, - 2.2478E-5, - 3.2269E-5, - 2.0226E-5, - 3.1833E-5 - ], - [ - 2.1356E-5, - 2.0004E-5, - 1.9901E-5, - 1.8612E-5, - 2.336E-5, - 1.8935E-5, - 1.9187E-5, - 2.5302E-5, - 1.8099E-5, - 3.1867E-5, - 2.6812E-5, - 2.4233E-5, - 1.7695E-5, - 1.7378E-5, - 3.5102E-5, - 1.7825E-5, - 2.3458E-5, - 1.942E-5, - 2.3688E-5, - 3.0584E-5, - 1.8507E-5, - 1.9984E-5, - 1.9354E-5, - 4.9397E-5, - 3.2538E-5, - 2.4161E-5, - 3.0751E-5, - 2.1821E-5, - 2.4078E-5, - 1.7775E-5, - 1.7291E-5, - 1.744E-5, - 1.8535E-5, - 1.7396E-5, - 1.9805E-5, - 2.4431E-5, - 1.7789E-5, - 3.3048E-5, - 1.7298E-5, - 4.9368E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.5085647500000002E-4, - "scoreError" : 1.6283513321888603E-5, - "scoreConfidence" : [ - 1.3457296167811142E-4, - 1.6713998832188862E-4 - ], - "scorePercentiles" : { - "0.0" : 5.9937E-5, - "50.0" : 1.507215E-4, - "90.0" : 2.4143620000000002E-4, - "95.0" : 2.7323774999999994E-4, - "99.0" : 3.462359500000002E-4, - "99.9" : 3.74866E-4, - "99.99" : 3.74866E-4, - "99.999" : 3.74866E-4, - "99.9999" : 3.74866E-4, - "100.0" : 3.74866E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.96103E-4, - 2.90326E-4, - 3.74866E-4, - 2.32002E-4, - 2.23338E-4, - 2.59337E-4, - 3.27718E-4, - 2.51324E-4, - 2.30297E-4, - 2.226E-4, - 2.15695E-4, - 2.84352E-4, - 2.69661E-4, - 2.894E-4, - 3.46423E-4, - 2.91646E-4, - 2.73426E-4, - 9.4104E-5, - 9.5189E-5, - 9.5513E-5, - 1.57373E-4, - 1.09877E-4, - 1.09571E-4, - 1.22852E-4, - 1.02446E-4, - 1.45621E-4, - 1.05996E-4, - 9.8675E-5, - 8.8976E-5, - 1.57332E-4, - 9.5813E-5, - 1.45647E-4, - 1.58024E-4, - 1.24387E-4, - 1.6942E-4, - 2.13988E-4, - 1.96796E-4, - 1.03669E-4, - 9.7939E-5, - 1.21009E-4 - ], - [ - 2.50161E-4, - 2.41946E-4, - 2.15894E-4, - 2.2472E-4, - 2.31422E-4, - 2.42668E-4, - 2.36848E-4, - 2.30434E-4, - 2.36251E-4, - 2.12868E-4, - 2.23064E-4, - 2.29196E-4, - 2.13802E-4, - 2.09846E-4, - 2.12585E-4, - 2.12838E-4, - 2.13157E-4, - 2.10605E-4, - 2.13486E-4, - 2.18151E-4, - 1.05701E-4, - 8.9845E-5, - 8.7E-5, - 9.1508E-5, - 9.0274E-5, - 8.4287E-5, - 9.7987E-5, - 9.667E-5, - 1.25444E-4, - 1.21743E-4, - 1.05537E-4, - 1.37435E-4, - 1.08287E-4, - 1.33981E-4, - 1.50147E-4, - 9.6558E-5, - 9.3621E-5, - 1.3326E-4, - 1.91238E-4, - 1.17037E-4 - ], - [ - 1.73246E-4, - 2.44601E-4, - 1.56392E-4, - 1.54849E-4, - 1.6071E-4, - 1.55554E-4, - 1.51201E-4, - 1.6041E-4, - 1.53309E-4, - 1.55217E-4, - 1.56053E-4, - 1.58912E-4, - 1.78742E-4, - 1.51613E-4, - 1.57757E-4, - 1.63444E-4, - 1.58163E-4, - 1.58691E-4, - 1.58962E-4, - 1.8399E-4, - 1.26128E-4, - 8.2229E-5, - 8.7124E-5, - 7.498E-5, - 7.1764E-5, - 1.1595E-4, - 6.632E-5, - 6.8115E-5, - 7.4938E-5, - 7.3374E-5, - 6.6485E-5, - 6.3362E-5, - 8.3412E-5, - 7.6246E-5, - 7.001E-5, - 6.4219E-5, - 6.4356E-5, - 6.5763E-5, - 6.5361E-5, - 6.5861E-5 - ], - [ - 2.28794E-4, - 2.34452E-4, - 2.15049E-4, - 2.22805E-4, - 2.17585E-4, - 2.09449E-4, - 2.12791E-4, - 2.15361E-4, - 2.67857E-4, - 2.34641E-4, - 2.11472E-4, - 2.10566E-4, - 2.05891E-4, - 2.24691E-4, - 2.29126E-4, - 2.21972E-4, - 2.2198E-4, - 2.45092E-4, - 2.50872E-4, - 1.14456E-4, - 1.1933E-4, - 1.00829E-4, - 9.0625E-5, - 9.16E-5, - 9.7443E-5, - 8.442E-5, - 9.2121E-5, - 1.07537E-4, - 1.08067E-4, - 1.04526E-4, - 1.0541E-4, - 1.42499E-4, - 1.0336E-4, - 1.06752E-4, - 9.0864E-5, - 8.7182E-5, - 9.629E-5, - 1.00735E-4, - 8.4317E-5, - 8.6513E-5 - ], - [ - 1.77265E-4, - 2.79867E-4, - 1.53898E-4, - 1.52042E-4, - 1.53111E-4, - 1.50489E-4, - 1.55037E-4, - 1.97783E-4, - 1.50192E-4, - 1.60868E-4, - 1.50954E-4, - 1.58274E-4, - 1.49605E-4, - 1.51062E-4, - 1.54843E-4, - 1.51172E-4, - 1.5676E-4, - 1.59973E-4, - 1.55097E-4, - 1.5654E-4, - 1.25145E-4, - 6.3165E-5, - 5.9937E-5, - 6.71E-5, - 6.1031E-5, - 6.4034E-5, - 6.329E-5, - 6.0872E-5, - 6.1405E-5, - 6.0613E-5, - 6.2358E-5, - 6.1443E-5, - 6.322E-5, - 6.2912E-5, - 9.8491E-5, - 6.4123E-5, - 6.1754E-5, - 6.7506E-5, - 6.7134E-5, - 6.1562E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 2.59396075E-4, - "scoreError" : 3.083245950291946E-5, - "scoreConfidence" : [ - 2.2856361549708054E-4, - 2.902285345029194E-4 - ], - "scorePercentiles" : { - "0.0" : 1.70802E-4, - "50.0" : 1.82025E-4, - "90.0" : 4.82823E-4, - "95.0" : 4.9065655E-4, - "99.0" : 5.067418599999999E-4, - "99.9" : 5.0721E-4, - "99.99" : 5.0721E-4, - "99.999" : 5.0721E-4, - "99.9999" : 5.0721E-4, - "100.0" : 5.0721E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.86472E-4, - 4.893E-4, - 4.8286E-4, - 4.80597E-4, - 4.92102E-4, - 4.92938E-4, - 5.05738E-4, - 5.02072E-4, - 5.0721E-4, - 4.99483E-4, - 2.01769E-4, - 1.8809E-4, - 1.89141E-4, - 1.86775E-4, - 1.84353E-4, - 1.9054E-4, - 1.83285E-4, - 1.82688E-4, - 1.81954E-4, - 1.82021E-4, - 1.87632E-4, - 1.82302E-4, - 1.8063E-4, - 1.81689E-4, - 1.8227E-4, - 1.83197E-4, - 1.82451E-4, - 1.82121E-4, - 1.8088E-4, - 1.81982E-4, - 1.81912E-4, - 2.05731E-4, - 2.36401E-4, - 1.85412E-4, - 1.83343E-4, - 1.80015E-4, - 2.17813E-4, - 1.82663E-4, - 1.82029E-4, - 1.83094E-4 - ], - [ - 4.80813E-4, - 4.7204E-4, - 4.79513E-4, - 4.72216E-4, - 4.89836E-4, - 4.90687E-4, - 5.06752E-4, - 4.95085E-4, - 4.89886E-4, - 4.85102E-4, - 2.23985E-4, - 1.78881E-4, - 1.73402E-4, - 1.77127E-4, - 1.72853E-4, - 1.7626E-4, - 1.73585E-4, - 1.71953E-4, - 1.71318E-4, - 1.83471E-4, - 1.76793E-4, - 1.73986E-4, - 1.71044E-4, - 1.7236E-4, - 1.72832E-4, - 1.75014E-4, - 1.7411E-4, - 1.72281E-4, - 1.73754E-4, - 1.71781E-4, - 1.73196E-4, - 2.19199E-4, - 1.83145E-4, - 1.72691E-4, - 1.71234E-4, - 1.7237E-4, - 1.73034E-4, - 1.73976E-4, - 2.98627E-4, - 1.76673E-4 - ], - [ - 4.87609E-4, - 4.94182E-4, - 4.73234E-4, - 4.75365E-4, - 4.7594E-4, - 4.86646E-4, - 4.82083E-4, - 4.8249E-4, - 4.79857E-4, - 4.90078E-4, - 2.66346E-4, - 1.80537E-4, - 1.74194E-4, - 1.77621E-4, - 1.75145E-4, - 1.89639E-4, - 1.74708E-4, - 1.74295E-4, - 1.78011E-4, - 1.78069E-4, - 2.3483E-4, - 1.8111E-4, - 1.7401E-4, - 1.79506E-4, - 1.78028E-4, - 1.78595E-4, - 1.80754E-4, - 1.78737E-4, - 1.80755E-4, - 1.81271E-4, - 1.83544E-4, - 1.85367E-4, - 2.24848E-4, - 1.8495E-4, - 1.86909E-4, - 1.81361E-4, - 1.79876E-4, - 1.80527E-4, - 1.77739E-4, - 1.79618E-4 - ], - [ - 4.73014E-4, - 4.85432E-4, - 4.77574E-4, - 4.78459E-4, - 4.76038E-4, - 4.76973E-4, - 4.77215E-4, - 4.70336E-4, - 4.71782E-4, - 4.81904E-4, - 1.8546E-4, - 1.76382E-4, - 1.74068E-4, - 1.75744E-4, - 1.75527E-4, - 2.20059E-4, - 1.73891E-4, - 1.7348E-4, - 1.73469E-4, - 1.73667E-4, - 2.19069E-4, - 1.71384E-4, - 1.71527E-4, - 1.74048E-4, - 1.75193E-4, - 1.73917E-4, - 1.84715E-4, - 1.77213E-4, - 2.27908E-4, - 1.72079E-4, - 1.74948E-4, - 1.9141E-4, - 2.32784E-4, - 1.78695E-4, - 1.76363E-4, - 1.76052E-4, - 1.90218E-4, - 1.91948E-4, - 1.89365E-4, - 1.74083E-4 - ], - [ - 4.7096E-4, - 4.74094E-4, - 4.71896E-4, - 4.74961E-4, - 4.70055E-4, - 4.65264E-4, - 4.72114E-4, - 4.65631E-4, - 4.68841E-4, - 4.70904E-4, - 1.85542E-4, - 1.76213E-4, - 1.77206E-4, - 1.89515E-4, - 1.71234E-4, - 1.7167E-4, - 1.7726E-4, - 1.70802E-4, - 1.72232E-4, - 1.77941E-4, - 2.16032E-4, - 1.72057E-4, - 1.73023E-4, - 1.72326E-4, - 1.79432E-4, - 1.76985E-4, - 1.75679E-4, - 1.71935E-4, - 1.73653E-4, - 1.72378E-4, - 1.73391E-4, - 2.78193E-4, - 3.42061E-4, - 1.80566E-4, - 1.76075E-4, - 1.77898E-4, - 1.74653E-4, - 1.77175E-4, - 1.78064E-4, - 1.75707E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0026458188200000005, - "scoreError" : 3.724748475858348E-4, - "scoreConfidence" : [ - 0.002273343972414166, - 0.003018293667585835 - ], - "scorePercentiles" : { - "0.0" : 0.001561146, - "50.0" : 0.0016262675, - "90.0" : 0.0049115806, - "95.0" : 0.00555910225, - "99.0" : 0.006832986540000008, - "99.9" : 0.007407361, - "99.99" : 0.007407361, - "99.999" : 0.007407361, - "99.9999" : 0.007407361, - "100.0" : 0.007407361 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001641989, - 0.004912416, - 0.004903287, - 0.001617115, - 0.001619366, - 0.001613995, - 0.001676385, - 0.001629409, - 0.00162608, - 0.001864641, - 0.001618135, - 0.001632043, - 0.004851429, - 0.005116439, - 0.005561573, - 0.005649646, - 0.001846712, - 0.00176171, - 0.001614585, - 0.001615055, - 0.001622779, - 0.001614204, - 0.001612416, - 0.00161248, - 0.004507489, - 0.001632372, - 0.001722502, - 0.001615179, - 0.001654336, - 0.001649497, - 0.001611956, - 0.001614044, - 0.001613091, - 0.001609711, - 0.002826759, - 0.004901012, - 0.005666035, - 0.005591654, - 0.005512158, - 0.005741125 - ], - [ - 0.00163345, - 0.004802275, - 0.004785467, - 0.001621456, - 0.001610303, - 0.001612834, - 0.001614965, - 0.001645905, - 0.001653464, - 0.00161203, - 0.001612382, - 0.001624008, - 0.004908265, - 0.004888519, - 0.004829976, - 0.004805187, - 0.001649555, - 0.001614817, - 0.001611951, - 0.001613486, - 0.001618236, - 0.001608243, - 0.001615133, - 0.001615379, - 0.001628312, - 0.001625681, - 0.001589984, - 0.001576798, - 0.001584208, - 0.001569824, - 0.001581784, - 0.001578142, - 0.001574592, - 0.002159507, - 0.004664558, - 0.004729665, - 0.004685121, - 0.004625908, - 0.004683018, - 0.004702209 - ], - [ - 0.001625449, - 0.004858113, - 0.007407361, - 0.001616555, - 0.001614296, - 0.001617008, - 0.001621733, - 0.001623486, - 0.001617283, - 0.001616672, - 0.00161198, - 0.001642648, - 0.005140848, - 0.005567264, - 0.005499269, - 0.005610425, - 0.001803282, - 0.001777246, - 0.001610869, - 0.001619417, - 0.001619689, - 0.001611039, - 0.001606866, - 0.001615226, - 0.001615989, - 0.001630316, - 0.001623571, - 0.001614745, - 0.001616502, - 0.001614786, - 0.001612351, - 0.001609353, - 0.001617442, - 0.001610724, - 0.003370399, - 0.004803693, - 0.004763557, - 0.004848208, - 0.006842215, - 0.005919369 - ], - [ - 0.001644044, - 0.004732261, - 0.004887935, - 0.001620162, - 0.00161723, - 0.00161233, - 0.001614257, - 0.00163061, - 0.00161835, - 0.001619528, - 0.001613228, - 0.001691423, - 0.004803902, - 0.004773331, - 0.004810127, - 0.004911949, - 0.001630546, - 0.001617261, - 0.001612901, - 0.001617071, - 0.001618758, - 0.001663554, - 0.001641042, - 0.001615507, - 0.001613841, - 0.001618242, - 0.001613297, - 0.001610104, - 0.001612195, - 0.001613323, - 0.001619444, - 0.001704985, - 0.00161015, - 0.002455064, - 0.004734826, - 0.004789269, - 0.004838491, - 0.004786511, - 0.005494829, - 0.004816777 - ], - [ - 0.001640827, - 0.004883599, - 0.00499595, - 0.001687183, - 0.001645451, - 0.00161552, - 0.001658437, - 0.001632225, - 0.001634155, - 0.001615853, - 0.001612684, - 0.001636025, - 0.004746813, - 0.004777993, - 0.004745469, - 0.004774109, - 0.001631113, - 0.001612841, - 0.001614664, - 0.001736354, - 0.00160188, - 0.001576585, - 0.001577288, - 0.001576213, - 0.001577689, - 0.001626455, - 0.001580743, - 0.001576203, - 0.001585418, - 0.001563689, - 0.001574219, - 0.001561146, - 0.001569171, - 0.0015727, - 0.002657493, - 0.004719635, - 0.005111205, - 0.004839825, - 0.004721634, - 0.005012003 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.01944036752500001, - "scoreError" : 0.0019381122121999547, - "scoreConfidence" : [ - 0.017502255312800055, - 0.021378479737199963 - ], - "scorePercentiles" : { - "0.0" : 0.01523974, - "50.0" : 0.016154019999999998, - "90.0" : 0.023280079800000002, - "95.0" : 0.046250580949999995, - "99.0" : 0.05107119785000001, - "99.9" : 0.054351501, - "99.99" : 0.054351501, - "99.999" : 0.054351501, - "99.9999" : 0.054351501, - "100.0" : 0.054351501 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.023285255, - 0.019056768, - 0.016776287, - 0.049765291, - 0.023015583, - 0.019926291, - 0.018215213, - 0.016834235, - 0.016000594, - 0.015836394, - 0.046882215, - 0.020992505, - 0.016098945, - 0.015919999, - 0.017016053, - 0.016223944, - 0.016161293, - 0.01569701, - 0.015936185, - 0.051079189, - 0.02060172, - 0.017295859, - 0.016840949, - 0.01698633, - 0.026069844, - 0.016757343, - 0.016704543, - 0.016836108, - 0.016736268, - 0.018965545, - 0.016714361, - 0.016983304, - 0.016619996, - 0.01785725, - 0.021979449, - 0.01651567, - 0.016152594, - 0.016063125, - 0.016251083, - 0.015816024 - ], - [ - 0.019784133, - 0.015991615, - 0.015811729, - 0.04964564, - 0.020925672, - 0.016333648, - 0.017777693, - 0.016042455, - 0.016100485, - 0.016623085, - 0.054351501, - 0.021479846, - 0.015834385, - 0.015920176, - 0.017074862, - 0.017518005, - 0.016162474, - 0.016433867, - 0.016011741, - 0.034015804, - 0.021221246, - 0.016138216, - 0.016126501, - 0.015881345, - 0.016617567, - 0.015992622, - 0.016453851, - 0.01597812, - 0.017210091, - 0.021132102, - 0.015858972, - 0.015883547, - 0.015832342, - 0.016248872, - 0.021451876, - 0.01616388, - 0.015888662, - 0.016032366, - 0.016101763, - 0.015950045 - ], - [ - 0.019826907, - 0.021497944, - 0.016138521, - 0.046133388, - 0.01523974, - 0.015660681, - 0.017292616, - 0.020530061, - 0.016093722, - 0.016341592, - 0.046256749, - 0.015779173, - 0.015746837, - 0.015611975, - 0.016996482, - 0.021577572, - 0.016406715, - 0.015906409, - 0.015832185, - 0.047790678, - 0.015803975, - 0.015824113, - 0.01590215, - 0.016162937, - 0.020576014, - 0.016621113, - 0.015987491, - 0.016135071, - 0.015875201, - 0.015948024, - 0.01573033, - 0.015933253, - 0.016090119, - 0.015618277, - 0.016851979, - 0.016172898, - 0.015540249, - 0.015570229, - 0.021071741, - 0.01572953 - ], - [ - 0.019621863, - 0.015919892, - 0.016440668, - 0.050280074, - 0.021711794, - 0.016093709, - 0.01724701, - 0.035826263, - 0.015851675, - 0.015913959, - 0.016038233, - 0.046758066, - 0.02070723, - 0.01574927, - 0.016246158, - 0.017122535, - 0.023233503, - 0.015860918, - 0.01596954, - 0.016019641, - 0.015924273, - 0.021923375, - 0.016140562, - 0.015742958, - 0.015724884, - 0.015605384, - 0.015393075, - 0.015979804, - 0.015999877, - 0.015615426, - 0.02309493, - 0.015699285, - 0.016015774, - 0.015666012, - 0.015603293, - 0.040047375, - 0.015951989, - 0.016035861, - 0.016161315, - 0.016155446 - ], - [ - 0.020121387, - 0.016181212, - 0.015955852, - 0.044898494, - 0.021693182, - 0.018934402, - 0.017377916, - 0.037992385, - 0.016095523, - 0.015798176, - 0.015810421, - 0.04724581, - 0.021034915, - 0.015818319, - 0.01575796, - 0.017352917, - 0.023365077, - 0.015735665, - 0.015861822, - 0.015877459, - 0.015976077, - 0.022347404, - 0.015880306, - 0.015829057, - 0.015863335, - 0.015665955, - 0.015656946, - 0.015884199, - 0.015996495, - 0.015776377, - 0.0158899, - 0.015765194, - 0.016394123, - 0.015749898, - 0.015928707, - 0.031877486, - 0.015623018, - 0.0160642, - 0.016818973, - 0.015810005 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1825934999999999E-4, - "scoreError" : 3.7452934349419985E-6, - "scoreConfidence" : [ - 1.14514056565058E-4, - 1.2200464343494198E-4 - ], - "scorePercentiles" : { - "0.0" : 1.10757E-4, - "50.0" : 1.15564E-4, - "90.0" : 1.2200210000000001E-4, - "95.0" : 1.3085164999999998E-4, - "99.0" : 2.1537974000000054E-4, - "99.9" : 3.01335E-4, - "99.99" : 3.01335E-4, - "99.999" : 3.01335E-4, - "99.9999" : 3.01335E-4, - "100.0" : 3.01335E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.36964E-4, - 1.26697E-4, - 1.15107E-4, - 1.14946E-4, - 1.16366E-4, - 1.14794E-4, - 1.16833E-4, - 1.14383E-4, - 1.14531E-4, - 1.20509E-4, - 1.26424E-4, - 1.1475E-4, - 1.15719E-4, - 1.14585E-4, - 1.20153E-4, - 1.16874E-4, - 1.13118E-4, - 1.16313E-4, - 1.18648E-4, - 1.17302E-4, - 1.13351E-4, - 1.11902E-4, - 1.13929E-4, - 1.13684E-4, - 1.17018E-4, - 1.1675E-4, - 1.15551E-4, - 1.16091E-4, - 1.49809E-4, - 1.16544E-4, - 1.1477E-4, - 1.16945E-4, - 1.18235E-4, - 1.17906E-4, - 1.33124E-4, - 1.14792E-4, - 1.21436E-4, - 1.19919E-4, - 1.18827E-4, - 1.16132E-4 - ], - [ - 1.29607E-4, - 1.27428E-4, - 1.14795E-4, - 1.18903E-4, - 1.12432E-4, - 1.11876E-4, - 1.14024E-4, - 1.15359E-4, - 1.14047E-4, - 1.12329E-4, - 1.17899E-4, - 1.12481E-4, - 1.20407E-4, - 1.13077E-4, - 1.13567E-4, - 1.11775E-4, - 1.11973E-4, - 1.12384E-4, - 1.16404E-4, - 1.18577E-4, - 1.15127E-4, - 1.16076E-4, - 1.12325E-4, - 1.14275E-4, - 1.12722E-4, - 1.16041E-4, - 1.15111E-4, - 1.13473E-4, - 1.19296E-4, - 1.16163E-4, - 1.15791E-4, - 1.18604E-4, - 1.16591E-4, - 1.16494E-4, - 1.14155E-4, - 1.16668E-4, - 1.14783E-4, - 1.18831E-4, - 1.15489E-4, - 1.18063E-4 - ], - [ - 1.28309E-4, - 1.29629E-4, - 1.14028E-4, - 1.12589E-4, - 1.12226E-4, - 1.15188E-4, - 1.18387E-4, - 1.13963E-4, - 1.14469E-4, - 1.17799E-4, - 1.12801E-4, - 1.12522E-4, - 1.12839E-4, - 1.14175E-4, - 1.13417E-4, - 1.12044E-4, - 1.18469E-4, - 1.1352E-4, - 1.12725E-4, - 1.18124E-4, - 1.13595E-4, - 1.13012E-4, - 1.13554E-4, - 1.17061E-4, - 1.15698E-4, - 1.16508E-4, - 1.15692E-4, - 1.16079E-4, - 1.19341E-4, - 1.19633E-4, - 1.15259E-4, - 1.13187E-4, - 1.13965E-4, - 1.12648E-4, - 1.15788E-4, - 1.15555E-4, - 1.13279E-4, - 1.17242E-4, - 1.12917E-4, - 1.13022E-4 - ], - [ - 1.30916E-4, - 3.01335E-4, - 1.16154E-4, - 1.12174E-4, - 1.15315E-4, - 1.15614E-4, - 1.14078E-4, - 1.15513E-4, - 1.15159E-4, - 1.13578E-4, - 1.13324E-4, - 1.17424E-4, - 1.1667E-4, - 1.15606E-4, - 1.17348E-4, - 1.15225E-4, - 1.18489E-4, - 1.14995E-4, - 1.15115E-4, - 1.17737E-4, - 1.15735E-4, - 1.12234E-4, - 1.1462E-4, - 1.13209E-4, - 1.14801E-4, - 1.15672E-4, - 1.55954E-4, - 1.3577E-4, - 1.14255E-4, - 1.14953E-4, - 1.18041E-4, - 1.16545E-4, - 1.14604E-4, - 1.15989E-4, - 1.13974E-4, - 1.15819E-4, - 1.23264E-4, - 1.16361E-4, - 1.15573E-4, - 1.14532E-4 - ], - [ - 1.34417E-4, - 1.25648E-4, - 1.13885E-4, - 1.17493E-4, - 1.13297E-4, - 1.13923E-4, - 1.22065E-4, - 1.14658E-4, - 1.14182E-4, - 1.12674E-4, - 1.12491E-4, - 1.1356E-4, - 1.12108E-4, - 1.13473E-4, - 1.15752E-4, - 1.10757E-4, - 1.15794E-4, - 1.1475E-4, - 1.14784E-4, - 1.17411E-4, - 1.1517E-4, - 1.1291E-4, - 1.14485E-4, - 1.17241E-4, - 1.16008E-4, - 1.18616E-4, - 2.1598E-4, - 1.12714E-4, - 1.32118E-4, - 1.13298E-4, - 1.14352E-4, - 1.20645E-4, - 1.17162E-4, - 1.1782E-4, - 1.16358E-4, - 1.16146E-4, - 1.15816E-4, - 1.23821E-4, - 1.18284E-4, - 1.18719E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.5134146500000016E-4, - "scoreError" : 1.6435579926037524E-5, - "scoreConfidence" : [ - 1.3490588507396263E-4, - 1.677770449260377E-4 - ], - "scorePercentiles" : { - "0.0" : 1.04726E-4, - "50.0" : 1.14947E-4, - "90.0" : 1.869011E-4, - "95.0" : 3.780382999999986E-4, - "99.0" : 4.2063475E-4, - "99.9" : 4.22929E-4, - "99.99" : 4.22929E-4, - "99.999" : 4.22929E-4, - "99.9999" : 4.22929E-4, - "100.0" : 4.22929E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.13967E-4, - 4.13698E-4, - 1.77167E-4, - 1.76215E-4, - 1.67389E-4, - 1.66302E-4, - 1.6835E-4, - 1.66028E-4, - 1.65342E-4, - 1.67569E-4, - 1.75149E-4, - 1.7219E-4, - 1.91097E-4, - 1.72024E-4, - 1.76005E-4, - 1.75809E-4, - 2.23988E-4, - 1.12063E-4, - 1.07176E-4, - 1.0732E-4, - 1.05318E-4, - 1.04887E-4, - 1.12351E-4, - 1.07378E-4, - 1.04956E-4, - 1.05532E-4, - 1.06885E-4, - 1.0545E-4, - 1.0754E-4, - 1.0572E-4, - 1.05747E-4, - 1.96382E-4, - 1.06411E-4, - 1.06938E-4, - 1.05E-4, - 1.04726E-4, - 1.06423E-4, - 1.05662E-4, - 1.07471E-4, - 1.05601E-4 - ], - [ - 4.08296E-4, - 4.14096E-4, - 1.78064E-4, - 1.72946E-4, - 1.76758E-4, - 1.6982E-4, - 1.73014E-4, - 1.66753E-4, - 1.73412E-4, - 1.72356E-4, - 1.75243E-4, - 1.72988E-4, - 1.7975E-4, - 1.77665E-4, - 1.76129E-4, - 1.76594E-4, - 2.25694E-4, - 1.1176E-4, - 1.08584E-4, - 1.08423E-4, - 1.08738E-4, - 1.05892E-4, - 1.05659E-4, - 1.06013E-4, - 1.05094E-4, - 1.0728E-4, - 1.05556E-4, - 1.05618E-4, - 1.05523E-4, - 1.05314E-4, - 1.05731E-4, - 1.05458E-4, - 1.06917E-4, - 1.05803E-4, - 1.05817E-4, - 1.06298E-4, - 1.0766E-4, - 1.10631E-4, - 1.06801E-4, - 1.06269E-4 - ], - [ - 4.2069E-4, - 4.10465E-4, - 1.79735E-4, - 1.74425E-4, - 1.73011E-4, - 1.68878E-4, - 1.68672E-4, - 1.6819E-4, - 1.68743E-4, - 1.66773E-4, - 1.77614E-4, - 1.79728E-4, - 1.86749E-4, - 1.732E-4, - 1.97363E-4, - 1.78578E-4, - 2.36807E-4, - 1.12527E-4, - 1.07354E-4, - 1.07592E-4, - 1.07189E-4, - 1.10403E-4, - 1.0499E-4, - 1.05679E-4, - 1.04946E-4, - 1.05131E-4, - 1.06265E-4, - 1.05279E-4, - 1.05178E-4, - 1.05384E-4, - 1.0662E-4, - 1.45345E-4, - 1.0615E-4, - 1.05693E-4, - 1.06253E-4, - 1.07317E-4, - 1.06977E-4, - 1.05911E-4, - 1.0939E-4, - 1.06713E-4 - ], - [ - 4.15165E-4, - 4.22929E-4, - 1.78008E-4, - 1.74847E-4, - 1.72696E-4, - 1.71024E-4, - 1.76709E-4, - 1.73445E-4, - 1.77065E-4, - 1.78445E-4, - 1.77974E-4, - 1.77119E-4, - 1.75281E-4, - 1.74882E-4, - 1.76603E-4, - 1.69674E-4, - 2.34166E-4, - 1.11425E-4, - 1.06844E-4, - 1.08257E-4, - 1.0539E-4, - 1.05462E-4, - 1.06082E-4, - 1.0627E-4, - 1.05892E-4, - 1.06212E-4, - 1.05924E-4, - 1.05924E-4, - 1.07109E-4, - 1.05422E-4, - 1.05866E-4, - 1.48209E-4, - 1.06762E-4, - 1.05157E-4, - 1.05337E-4, - 1.04838E-4, - 1.05424E-4, - 1.06436E-4, - 1.05889E-4, - 1.06622E-4 - ], - [ - 4.00278E-4, - 3.84252E-4, - 1.86918E-4, - 1.7957E-4, - 1.86163E-4, - 1.82831E-4, - 1.78159E-4, - 1.77871E-4, - 1.78445E-4, - 1.79782E-4, - 1.89607E-4, - 1.85787E-4, - 1.81017E-4, - 1.83881E-4, - 1.84659E-4, - 1.80629E-4, - 2.59978E-4, - 1.19643E-4, - 1.16418E-4, - 1.37143E-4, - 1.15646E-4, - 1.14332E-4, - 1.14904E-4, - 1.15154E-4, - 1.15015E-4, - 1.14518E-4, - 1.13656E-4, - 1.14576E-4, - 1.14663E-4, - 1.14469E-4, - 1.15284E-4, - 1.1499E-4, - 1.15045E-4, - 1.14572E-4, - 1.13848E-4, - 1.13216E-4, - 1.15034E-4, - 1.14685E-4, - 1.18894E-4, - 1.18426E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0024601392450000004, - "scoreError" : 0.0010548092536902507, - "scoreConfidence" : [ - 0.0014053299913097496, - 0.003514948498690251 - ], - "scorePercentiles" : { - "0.0" : 0.001031204, - "50.0" : 0.0010644295000000002, - "90.0" : 0.0017554603, - "95.0" : 0.01783406405, - "99.0" : 0.018756401080000006, - "99.9" : 0.019435475, - "99.99" : 0.019435475, - "99.999" : 0.019435475, - "99.9999" : 0.019435475, - "100.0" : 0.019435475 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001072861, - 0.001078154, - 0.001102116, - 0.001737676, - 0.001748209, - 0.017896372, - 0.001063717, - 0.001061816, - 0.001060712, - 0.001063329, - 0.00105633, - 0.017834479, - 0.001035089, - 0.001034462, - 0.001038337, - 0.001034966, - 0.001039787, - 0.001040573, - 0.001714653, - 0.001746362, - 0.001734356, - 0.001714518, - 0.001699058, - 0.017861109, - 0.00103431, - 0.00103621, - 0.001039608, - 0.001036034, - 0.001039599, - 0.001031301, - 0.001040688, - 0.00112505, - 0.001203795, - 0.001039759, - 0.001074845, - 0.001035093, - 0.001041456, - 0.00103659, - 0.001250803, - 0.001210056 - ], - [ - 0.001064721, - 0.001078123, - 0.001112574, - 0.001724965, - 0.001756266, - 0.017962556, - 0.001061451, - 0.001063299, - 0.001062569, - 0.00106058, - 0.001055, - 0.017745105, - 0.001062002, - 0.001061004, - 0.001058914, - 0.001058813, - 0.001070598, - 0.00106206, - 0.001706192, - 0.001738778, - 0.00173548, - 0.001725894, - 0.00172879, - 0.01806904, - 0.00106191, - 0.001065488, - 0.001064487, - 0.001065245, - 0.001064361, - 0.001063011, - 0.001058151, - 0.001064581, - 0.001064548, - 0.001042095, - 0.001068396, - 0.001033948, - 0.001039619, - 0.001036321, - 0.001038144, - 0.001036995 - ], - [ - 0.001040736, - 0.001203414, - 0.001078115, - 0.001667255, - 0.001737603, - 0.01782618, - 0.001060841, - 0.001060625, - 0.001057795, - 0.001060147, - 0.001058504, - 0.017746356, - 0.001064521, - 0.001060336, - 0.001057498, - 0.00107789, - 0.001076477, - 0.001084607, - 0.001717115, - 0.001733872, - 0.001732883, - 0.001761166, - 0.002107207, - 0.019435475, - 0.001059113, - 0.001260692, - 0.001248574, - 0.00124398, - 0.001147893, - 0.001057169, - 0.001062513, - 0.001065647, - 0.00110032, - 0.001156575, - 0.001213692, - 0.001061069, - 0.001069345, - 0.001061417, - 0.001061963, - 0.001064388 - ], - [ - 0.001040893, - 0.001041342, - 0.001078708, - 0.0016595, - 0.001710196, - 0.018113621, - 0.001034693, - 0.001035923, - 0.00103999, - 0.001037507, - 0.001036075, - 0.017693007, - 0.001063687, - 0.001061428, - 0.001067295, - 0.001060865, - 0.001067075, - 0.001063779, - 0.001695695, - 0.001773727, - 0.001714052, - 0.001727551, - 0.001738919, - 0.018437728, - 0.001037539, - 0.0010409, - 0.001051733, - 0.001038868, - 0.001040719, - 0.001047051, - 0.001040525, - 0.001262258, - 0.00103945, - 0.001037713, - 0.001070787, - 0.00103948, - 0.001042968, - 0.001062222, - 0.001066581, - 0.001063244 - ], - [ - 0.001040035, - 0.001078096, - 0.001080195, - 0.001670866, - 0.001699854, - 0.017967355, - 0.001033334, - 0.001035129, - 0.001031445, - 0.001037198, - 0.001031204, - 0.017751549, - 0.00104476, - 0.001032935, - 0.00103648, - 0.001034922, - 0.001039896, - 0.001037799, - 0.001656975, - 0.001692586, - 0.001728575, - 0.001841332, - 0.001742335, - 0.01875962, - 0.001057969, - 0.001065187, - 0.001067789, - 0.001074635, - 0.001065806, - 0.00107072, - 0.001062706, - 0.001063995, - 0.00106211, - 0.001064471, - 0.001104204, - 0.001084798, - 0.001043676, - 0.001109279, - 0.001034171, - 0.001039284 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.017118883294999995, - "scoreError" : 0.006629950539653628, - "scoreConfidence" : [ - 0.010488932755346366, - 0.02374883383465362 - ], - "scorePercentiles" : { - "0.0" : 0.010169741, - "50.0" : 0.0106741645, - "90.0" : 0.011109742, - "95.0" : 0.12600573709999868, - "99.0" : 0.14272167963, - "99.9" : 0.146324271, - "99.99" : 0.146324271, - "99.999" : 0.146324271, - "99.9999" : 0.146324271, - "100.0" : 0.146324271 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.010860657, - 0.141912459, - 0.010502557, - 0.010257646, - 0.010531558, - 0.010725375, - 0.010851223, - 0.010974195, - 0.010766343, - 0.010912489, - 0.141483319, - 0.010566327, - 0.01082226, - 0.010504381, - 0.010713519, - 0.010992787, - 0.011080375, - 0.010434018, - 0.010904795, - 0.010749555, - 0.010613462, - 0.133977192, - 0.011299381, - 0.010880943, - 0.010403146, - 0.010518319, - 0.010169741, - 0.011442237, - 0.010566656, - 0.010320025, - 0.010649807, - 0.010431594, - 0.010631924, - 0.010587802, - 0.010289876, - 0.010805241, - 0.010300966, - 0.011965285, - 0.010339106, - 0.010384316 - ], - [ - 0.011112766, - 0.011421263, - 0.010713608, - 0.011060613, - 0.010686825, - 0.010532701, - 0.010902187, - 0.010885258, - 0.010547931, - 0.010480179, - 0.010634922, - 0.010660365, - 0.010404303, - 0.010668593, - 0.010615362, - 0.010599695, - 0.010802789, - 0.010984443, - 0.010630458, - 0.010600906, - 0.010560614, - 0.010588959, - 0.010338695, - 0.010602888, - 0.010621062, - 0.010599502, - 0.010722882, - 0.01045618, - 0.010669671, - 0.010486405, - 0.010803767, - 0.131935026, - 0.010629166, - 0.010627758, - 0.010580396, - 0.010514398, - 0.010649863, - 0.010624128, - 0.010716672, - 0.010590243 - ], - [ - 0.010984691, - 0.142727264, - 0.011337156, - 0.011317687, - 0.010439877, - 0.010646833, - 0.010980504, - 0.010740781, - 0.010539889, - 0.010728374, - 0.142168827, - 0.010769838, - 0.010451219, - 0.013349248, - 0.011282461, - 0.010829311, - 0.010724094, - 0.010528761, - 0.010589168, - 0.010676708, - 0.010663738, - 0.134666133, - 0.010756881, - 0.010453349, - 0.010436474, - 0.010715887, - 0.010322129, - 0.010730989, - 0.010553881, - 0.011148916, - 0.010976642, - 0.010580572, - 0.010783126, - 0.010420527, - 0.010782135, - 0.010478048, - 0.010572517, - 0.010620726, - 0.010623551, - 0.011082526 - ], - [ - 0.010886405, - 0.010573641, - 0.011020508, - 0.010416943, - 0.010680921, - 0.010689526, - 0.01087156, - 0.010677344, - 0.0107125, - 0.010757008, - 0.01085479, - 0.010617031, - 0.010456257, - 0.010698293, - 0.010671883, - 0.010699871, - 0.010684861, - 0.010739043, - 0.010793895, - 0.010687273, - 0.010727872, - 0.010775868, - 0.010771738, - 0.010753789, - 0.010478884, - 0.010479863, - 0.010632363, - 0.010685959, - 0.010785581, - 0.010539363, - 0.010773312, - 0.010568506, - 0.010756559, - 0.010694645, - 0.010747223, - 0.010685147, - 0.010302887, - 0.01088228, - 0.010742906, - 0.010852103 - ], - [ - 0.010912664, - 0.146324271, - 0.01048435, - 0.010504689, - 0.010580496, - 0.010409538, - 0.010954114, - 0.010676446, - 0.010645088, - 0.010666726, - 0.141123486, - 0.010718236, - 0.010473838, - 0.010408836, - 0.01058274, - 0.010418044, - 0.010475693, - 0.010616968, - 0.010596095, - 0.010900569, - 0.010548382, - 0.010535948, - 0.010724393, - 0.010954027, - 0.010612178, - 0.010632689, - 0.010578366, - 0.010710501, - 0.010491071, - 0.010656214, - 0.134534859, - 0.010717414, - 0.010556927, - 0.010652965, - 0.010722263, - 0.010622508, - 0.010715477, - 0.010627779, - 0.010689773, - 0.0106259 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 8.731592999999996E-5, - "scoreError" : 2.3834368103813865E-5, - "scoreConfidence" : [ - 6.34815618961861E-5, - 1.1115029810381381E-4 - ], - "scorePercentiles" : { - "0.0" : 1.4574E-5, - "50.0" : 5.2226E-5, - "90.0" : 2.796342E-4, - "95.0" : 2.8341735E-4, - "99.0" : 2.8811742E-4, - "99.9" : 3.25378E-4, - "99.99" : 3.25378E-4, - "99.999" : 3.25378E-4, - "99.9999" : 3.25378E-4, - "100.0" : 3.25378E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.77688E-4, - 2.78827E-4, - 2.78863E-4, - 2.78786E-4, - 3.25378E-4, - 2.81848E-4, - 2.80963E-4, - 2.83472E-4, - 6.0661E-5, - 5.2696E-5, - 5.3328E-5, - 5.2689E-5, - 5.3083E-5, - 5.2056E-5, - 5.224E-5, - 7.1291E-5, - 5.2139E-5, - 5.4031E-5, - 5.3482E-5, - 5.1565E-5, - 1.13785E-4, - 5.1665E-5, - 1.01858E-4, - 1.6402E-5, - 1.5416E-5, - 1.6329E-5, - 1.5892E-5, - 1.5219E-5, - 1.518E-5, - 1.7209E-5, - 1.7002E-5, - 1.6679E-5, - 1.603E-5, - 1.6463E-5, - 1.5536E-5, - 1.6285E-5, - 1.7311E-5, - 1.6121E-5, - 1.6539E-5, - 1.5676E-5 - ], - [ - 2.79816E-4, - 2.79438E-4, - 2.7829E-4, - 2.77896E-4, - 2.7762E-4, - 2.80893E-4, - 2.77418E-4, - 2.80288E-4, - 6.1375E-5, - 5.3186E-5, - 5.2544E-5, - 5.2545E-5, - 5.2212E-5, - 5.2048E-5, - 5.1882E-5, - 6.8635E-5, - 5.2166E-5, - 5.3288E-5, - 5.2785E-5, - 5.0999E-5, - 1.28471E-4, - 5.5035E-5, - 1.08102E-4, - 1.5192E-5, - 1.5274E-5, - 1.4574E-5, - 1.479E-5, - 2.2274E-5, - 1.6371E-5, - 1.5619E-5, - 1.6318E-5, - 1.652E-5, - 1.6454E-5, - 1.5176E-5, - 1.5908E-5, - 1.5429E-5, - 1.5263E-5, - 1.58E-5, - 1.5444E-5, - 1.7078E-5 - ], - [ - 2.79636E-4, - 2.78531E-4, - 2.78275E-4, - 2.78612E-4, - 2.7674E-4, - 2.79618E-4, - 2.78933E-4, - 2.8128E-4, - 6.1924E-5, - 5.3998E-5, - 5.3112E-5, - 5.3334E-5, - 5.3751E-5, - 5.2295E-5, - 5.2321E-5, - 7.9297E-5, - 5.2381E-5, - 5.3596E-5, - 5.423E-5, - 5.2822E-5, - 1.51936E-4, - 5.1612E-5, - 1.0802E-4, - 1.6682E-5, - 1.5844E-5, - 1.5964E-5, - 1.5836E-5, - 1.6407E-5, - 1.6162E-5, - 1.5492E-5, - 1.75E-5, - 1.7111E-5, - 1.6868E-5, - 1.5091E-5, - 1.5629E-5, - 1.5785E-5, - 1.6261E-5, - 1.5867E-5, - 1.579E-5, - 1.6243E-5 - ], - [ - 2.83724E-4, - 2.85326E-4, - 2.86149E-4, - 2.87169E-4, - 2.83908E-4, - 2.84502E-4, - 2.88127E-4, - 2.78976E-4, - 6.2257E-5, - 5.398E-5, - 5.4325E-5, - 5.351E-5, - 5.3912E-5, - 5.2788E-5, - 5.2401E-5, - 6.8422E-5, - 5.4978E-5, - 5.6272E-5, - 5.5747E-5, - 5.1639E-5, - 1.09669E-4, - 5.2054E-5, - 1.03544E-4, - 3.0068E-5, - 1.5081E-5, - 1.4625E-5, - 1.5784E-5, - 1.5558E-5, - 1.5978E-5, - 1.5984E-5, - 1.676E-5, - 1.6777E-5, - 1.6515E-5, - 1.6244E-5, - 1.4964E-5, - 1.478E-5, - 1.6648E-5, - 1.5502E-5, - 1.6308E-5, - 1.614E-5 - ], - [ - 2.79102E-4, - 2.82379E-4, - 2.78219E-4, - 2.80935E-4, - 2.7831E-4, - 2.80929E-4, - 2.79318E-4, - 2.87048E-4, - 6.069E-5, - 5.3664E-5, - 5.2391E-5, - 5.1984E-5, - 5.2958E-5, - 5.3454E-5, - 5.3269E-5, - 8.9247E-5, - 5.2804E-5, - 5.3342E-5, - 5.3965E-5, - 5.103E-5, - 1.66377E-4, - 5.0932E-5, - 9.9688E-5, - 1.5196E-5, - 1.6341E-5, - 2.2791E-5, - 1.6292E-5, - 1.6136E-5, - 1.6054E-5, - 1.5848E-5, - 1.6118E-5, - 1.5988E-5, - 1.6336E-5, - 1.8567E-5, - 1.7023E-5, - 1.6038E-5, - 1.6572E-5, - 1.6706E-5, - 1.8722E-5, - 2.4443E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.9222423500000004E-4, - "scoreError" : 1.1269304230169972E-5, - "scoreConfidence" : [ - 1.8095493076983007E-4, - 2.0349353923017002E-4 - ], - "scorePercentiles" : { - "0.0" : 1.37196E-4, - "50.0" : 1.72587E-4, - "90.0" : 2.270692E-4, - "95.0" : 2.5148379999999983E-4, - "99.0" : 4.187417000000002E-4, - "99.9" : 4.75658E-4, - "99.99" : 4.75658E-4, - "99.999" : 4.75658E-4, - "99.9999" : 4.75658E-4, - "100.0" : 4.75658E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.43981E-4, - 1.49457E-4, - 1.38904E-4, - 1.38064E-4, - 1.42417E-4, - 1.40324E-4, - 3.76927E-4, - 2.23079E-4, - 2.52373E-4, - 2.2541E-4, - 2.23503E-4, - 1.67608E-4, - 1.6747E-4, - 2.2307E-4, - 1.68567E-4, - 1.70957E-4, - 1.72351E-4, - 1.7493E-4, - 1.67616E-4, - 1.73249E-4, - 1.72516E-4, - 2.26972E-4, - 2.23448E-4, - 2.73344E-4, - 2.26614E-4, - 2.24388E-4, - 2.30979E-4, - 2.26253E-4, - 1.71085E-4, - 2.25695E-4, - 1.77258E-4, - 1.74905E-4, - 1.75891E-4, - 1.71652E-4, - 2.2439E-4, - 1.68453E-4, - 1.66989E-4, - 1.68315E-4, - 1.65479E-4, - 1.6739E-4 - ], - [ - 1.41084E-4, - 1.44576E-4, - 2.03956E-4, - 1.37196E-4, - 1.4599E-4, - 1.38296E-4, - 4.18959E-4, - 1.67724E-4, - 1.75026E-4, - 2.31239E-4, - 2.25368E-4, - 1.67567E-4, - 1.68924E-4, - 1.63294E-4, - 2.27937E-4, - 2.24367E-4, - 1.73908E-4, - 1.72658E-4, - 1.66157E-4, - 1.68913E-4, - 1.66617E-4, - 2.26161E-4, - 1.66085E-4, - 2.80524E-4, - 2.25238E-4, - 2.24203E-4, - 2.30358E-4, - 2.27365E-4, - 1.74042E-4, - 2.24825E-4, - 1.71335E-4, - 2.23549E-4, - 1.71536E-4, - 1.65203E-4, - 2.24472E-4, - 2.22765E-4, - 2.23681E-4, - 1.70495E-4, - 2.26878E-4, - 2.24439E-4 - ], - [ - 2.06189E-4, - 2.04529E-4, - 1.37392E-4, - 1.47677E-4, - 1.46298E-4, - 1.39863E-4, - 3.86682E-4, - 1.66356E-4, - 1.75872E-4, - 2.31238E-4, - 2.22495E-4, - 2.23821E-4, - 1.75336E-4, - 1.72283E-4, - 1.70103E-4, - 1.63004E-4, - 1.73603E-4, - 1.81032E-4, - 1.6907E-4, - 1.71698E-4, - 1.65741E-4, - 2.23672E-4, - 1.67413E-4, - 2.77159E-4, - 2.27507E-4, - 1.6934E-4, - 1.7731E-4, - 1.71913E-4, - 1.69426E-4, - 1.66013E-4, - 2.22928E-4, - 2.28563E-4, - 1.71229E-4, - 2.22966E-4, - 2.23569E-4, - 1.67219E-4, - 1.66169E-4, - 2.24876E-4, - 2.23075E-4, - 1.68392E-4 - ], - [ - 2.05207E-4, - 2.03422E-4, - 1.38569E-4, - 1.40615E-4, - 2.11216E-4, - 2.0529E-4, - 4.75658E-4, - 1.65938E-4, - 1.67444E-4, - 1.71123E-4, - 2.24193E-4, - 1.64574E-4, - 1.63432E-4, - 1.6833E-4, - 1.69436E-4, - 2.23132E-4, - 1.83426E-4, - 1.7523E-4, - 1.67638E-4, - 1.73687E-4, - 2.23402E-4, - 1.65482E-4, - 2.23983E-4, - 2.77243E-4, - 1.74489E-4, - 2.24182E-4, - 1.79363E-4, - 1.74012E-4, - 1.67374E-4, - 1.70092E-4, - 1.71926E-4, - 2.24791E-4, - 1.73009E-4, - 1.65989E-4, - 2.26765E-4, - 2.24802E-4, - 1.69172E-4, - 1.65178E-4, - 1.71342E-4, - 1.68098E-4 - ], - [ - 1.4463E-4, - 1.42977E-4, - 1.38518E-4, - 1.41592E-4, - 1.43744E-4, - 1.37649E-4, - 3.97229E-4, - 1.64139E-4, - 2.2708E-4, - 2.25311E-4, - 1.68513E-4, - 1.67379E-4, - 1.69931E-4, - 2.24226E-4, - 2.26018E-4, - 1.64994E-4, - 1.78499E-4, - 1.75942E-4, - 1.67267E-4, - 1.65643E-4, - 1.66916E-4, - 1.66992E-4, - 1.65757E-4, - 2.34589E-4, - 1.72112E-4, - 1.68365E-4, - 1.8901E-4, - 1.78807E-4, - 1.78427E-4, - 2.26194E-4, - 2.24414E-4, - 2.25074E-4, - 1.73803E-4, - 2.26365E-4, - 1.66931E-4, - 1.66072E-4, - 1.68169E-4, - 1.66422E-4, - 1.69193E-4, - 1.67496E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0024204378449999998, - "scoreError" : 3.302155193117049E-4, - "scoreConfidence" : [ - 0.002090222325688295, - 0.0027506533643117045 - ], - "scorePercentiles" : { - "0.0" : 0.001397437, - "50.0" : 0.0018557550000000002, - "90.0" : 0.003990120000000002, - "95.0" : 0.0057593140999999985, - "99.0" : 0.00774959012, - "99.9" : 0.007758316, - "99.99" : 0.007758316, - "99.999" : 0.007758316, - "99.9999" : 0.007758316, - "100.0" : 0.007758316 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001745664, - 0.0027131, - 0.001411746, - 0.002309932, - 0.003657741, - 0.002384034, - 0.002465791, - 0.002482488, - 0.001781463, - 0.001952838, - 0.004638187, - 0.001953914, - 0.00184541, - 0.001780518, - 0.001739404, - 0.002545777, - 0.00540997, - 0.002397603, - 0.002514014, - 0.001719634, - 0.001719102, - 0.00161551, - 0.002128134, - 0.00211726, - 0.001642201, - 0.007519429, - 0.001806662, - 0.001880757, - 0.001836457, - 0.002544415, - 0.001715885, - 0.001719018, - 0.001815001, - 0.003153637, - 0.007551237, - 0.001824258, - 0.001909221, - 0.001839952, - 0.002612655, - 0.00246977 - ], - [ - 0.001442322, - 0.002011837, - 0.002033622, - 0.002039997, - 0.002907797, - 0.002316592, - 0.001445979, - 0.00205532, - 0.001516328, - 0.001975158, - 0.003105472, - 0.002041894, - 0.001414324, - 0.001401971, - 0.001403063, - 0.001399951, - 0.007733267, - 0.001949463, - 0.002731938, - 0.001874987, - 0.001786053, - 0.002491656, - 0.001727823, - 0.001721071, - 0.001704466, - 0.005765185, - 0.001691181, - 0.001779876, - 0.002500895, - 0.001719725, - 0.001686103, - 0.001600202, - 0.001418156, - 0.002038438, - 0.007749755, - 0.001788134, - 0.001880717, - 0.001841581, - 0.001791688, - 0.001756385 - ], - [ - 0.001775601, - 0.002735682, - 0.001420411, - 0.002048675, - 0.004281168, - 0.001641772, - 0.001760078, - 0.002463345, - 0.002528191, - 0.002049271, - 0.003273035, - 0.001447208, - 0.001399506, - 0.0016476, - 0.001397437, - 0.001405071, - 0.005400093, - 0.002398656, - 0.001760074, - 0.001746726, - 0.00242473, - 0.001651081, - 0.002194262, - 0.001469919, - 0.002467302, - 0.007758316, - 0.002645916, - 0.00272366, - 0.001859802, - 0.002609815, - 0.001763405, - 0.001741617, - 0.002467746, - 0.001571618, - 0.005511538, - 0.001680717, - 0.001749767, - 0.002460556, - 0.001722213, - 0.001641792 - ], - [ - 0.001483534, - 0.001963648, - 0.001449759, - 0.001448889, - 0.004027051, - 0.002370715, - 0.002502064, - 0.002511575, - 0.002583883, - 0.002710064, - 0.004693267, - 0.001708671, - 0.001839147, - 0.00179692, - 0.001787236, - 0.001852523, - 0.007712446, - 0.002685462, - 0.002744269, - 0.001872445, - 0.001829839, - 0.001761559, - 0.002454401, - 0.001801923, - 0.002640974, - 0.007187758, - 0.001778286, - 0.002730209, - 0.001858987, - 0.001795227, - 0.001757146, - 0.001720565, - 0.001789837, - 0.002920429, - 0.005647767, - 0.00243928, - 0.001761841, - 0.001718811, - 0.001689592, - 0.00230008 - ], - [ - 0.001746625, - 0.002095294, - 0.002074834, - 0.002035362, - 0.003465275, - 0.001541023, - 0.00219736, - 0.001915782, - 0.00163959, - 0.002004697, - 0.004746331, - 0.002428073, - 0.001793293, - 0.001783592, - 0.001758206, - 0.001723515, - 0.007558363, - 0.002681097, - 0.002731805, - 0.001843867, - 0.001810651, - 0.001721939, - 0.001727855, - 0.001716284, - 0.001878291, - 0.005525686, - 0.001781841, - 0.001782354, - 0.001718423, - 0.001728554, - 0.002438074, - 0.001732313, - 0.00162812, - 0.00153538, - 0.007588053, - 0.001808885, - 0.00272606, - 0.001843202, - 0.001779432, - 0.001718576 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.023899844045000007, - "scoreError" : 0.0013203635662903158, - "scoreConfidence" : [ - 0.022579480478709692, - 0.025220207611290322 - ], - "scorePercentiles" : { - "0.0" : 0.016214157, - "50.0" : 0.022965256500000003, - "90.0" : 0.0310706738, - "95.0" : 0.0339531378, - "99.0" : 0.0425152086, - "99.9" : 0.049356898, - "99.99" : 0.049356898, - "99.999" : 0.049356898, - "99.9999" : 0.049356898, - "100.0" : 0.049356898 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.049356898, - 0.030399854, - 0.034517446, - 0.021744687, - 0.018066976, - 0.029130475, - 0.019803874, - 0.021327273, - 0.031345529, - 0.032635802, - 0.016936038, - 0.022622295, - 0.025586448, - 0.018722934, - 0.019454503, - 0.025086184, - 0.017138199, - 0.023197128, - 0.026103439, - 0.019952901, - 0.019345258, - 0.025343693, - 0.016905899, - 0.022989648, - 0.020662292, - 0.022940865, - 0.019336007, - 0.026895438, - 0.017501235, - 0.027419478, - 0.027383953, - 0.020018598, - 0.020229185, - 0.028040608, - 0.021246802, - 0.016963589, - 0.020635436, - 0.023555534, - 0.021254746, - 0.019575384 - ], - [ - 0.033957788, - 0.029715953, - 0.033808759, - 0.026887503, - 0.017048241, - 0.027576523, - 0.020268363, - 0.023777886, - 0.030020789, - 0.032339754, - 0.017148399, - 0.020816815, - 0.027375078, - 0.023615661, - 0.030640877, - 0.029186006, - 0.017478529, - 0.017057488, - 0.021911176, - 0.02837971, - 0.02011902, - 0.019357808, - 0.026439817, - 0.017033769, - 0.024016054, - 0.019832973, - 0.019058614, - 0.019375611, - 0.025189386, - 0.018331978, - 0.023245872, - 0.019967352, - 0.019987714, - 0.018531887, - 0.025590493, - 0.01671666, - 0.024229138, - 0.01990028, - 0.01997619, - 0.019608635 - ], - [ - 0.025765932, - 0.03004115, - 0.042518237, - 0.025270103, - 0.024826801, - 0.029569068, - 0.019788824, - 0.028719742, - 0.031143327, - 0.036079048, - 0.017020053, - 0.022454849, - 0.020407092, - 0.022678646, - 0.036468211, - 0.028856589, - 0.017764019, - 0.01711552, - 0.022668652, - 0.028010959, - 0.025362179, - 0.019521522, - 0.026955843, - 0.021572288, - 0.023731686, - 0.019691939, - 0.022475016, - 0.023336853, - 0.031753788, - 0.017345668, - 0.024223184, - 0.026712267, - 0.019772538, - 0.023206062, - 0.026758331, - 0.017142335, - 0.022674179, - 0.02129695, - 0.022106822, - 0.019703535 - ], - [ - 0.027136397, - 0.0308429, - 0.042215397, - 0.025718259, - 0.0170407, - 0.027994298, - 0.020652098, - 0.02362418, - 0.031076999, - 0.028677479, - 0.017061917, - 0.020309429, - 0.027140003, - 0.022431174, - 0.030601242, - 0.036360054, - 0.017567896, - 0.016819837, - 0.021995351, - 0.025663596, - 0.021416039, - 0.018721816, - 0.023958168, - 0.016961319, - 0.023781328, - 0.020752712, - 0.022443531, - 0.023310813, - 0.030955777, - 0.024597566, - 0.024557114, - 0.028941767, - 0.023827487, - 0.01985028, - 0.026046325, - 0.017555459, - 0.035066724, - 0.029490333, - 0.02190043, - 0.019682997 - ], - [ - 0.024674474, - 0.031951488, - 0.033864784, - 0.026739056, - 0.017259538, - 0.023761075, - 0.024658144, - 0.029195269, - 0.031013747, - 0.038484694, - 0.017132464, - 0.016214157, - 0.029238148, - 0.023565681, - 0.030143608, - 0.018996242, - 0.02282188, - 0.018242949, - 0.031709839, - 0.02276625, - 0.021673594, - 0.019920493, - 0.025564011, - 0.016857949, - 0.023565184, - 0.019966135, - 0.019942526, - 0.018688435, - 0.027346612, - 0.017257977, - 0.023574967, - 0.022248581, - 0.019992454, - 0.023639304, - 0.02775663, - 0.018834853, - 0.020314446, - 0.020645658, - 0.025043855, - 0.02055158 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 9.52124E-6, - "scoreError" : 4.75693155604712E-7, - "scoreConfidence" : [ - 9.04554684439529E-6, - 9.996933155604712E-6 - ], - "scorePercentiles" : { - "0.0" : 6.392E-6, - "50.0" : 9.1705E-6, - "90.0" : 1.15963E-5, - "95.0" : 1.2772349999999998E-5, - "99.0" : 1.570258E-5, - "99.9" : 2.3767E-5, - "99.99" : 2.3767E-5, - "99.999" : 2.3767E-5, - "99.9999" : 2.3767E-5, - "100.0" : 2.3767E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.3054E-5, - 1.1318E-5, - 1.1598E-5, - 1.0372E-5, - 1.4158E-5, - 1.239E-5, - 1.1564E-5, - 1.1317E-5, - 1.1174E-5, - 1.0574E-5, - 1.1772E-5, - 1.1135E-5, - 1.1614E-5, - 1.2782E-5, - 1.1541E-5, - 1.0783E-5, - 1.0465E-5, - 1.5661E-5, - 1.1037E-5, - 1.0981E-5, - 1.2782E-5, - 1.0636E-5, - 1.2589E-5, - 1.017E-5, - 9.445E-6, - 9.215E-6, - 9.908E-6, - 8.713E-6, - 8.059E-6, - 8.073E-6, - 7.85E-6, - 7.778E-6, - 8.741E-6, - 1.0966E-5, - 8.766E-6, - 7.809E-6, - 8.891E-6, - 1.1935E-5, - 8.945E-6, - 8.239E-6 - ], - [ - 1.2019E-5, - 1.0365E-5, - 1.0897E-5, - 1.0394E-5, - 1.0088E-5, - 1.0766E-5, - 1.0752E-5, - 1.0332E-5, - 1.1344E-5, - 1.0225E-5, - 1.0969E-5, - 1.1254E-5, - 1.0684E-5, - 1.0766E-5, - 1.291E-5, - 9.842E-6, - 1.0311E-5, - 1.5703E-5, - 1.0058E-5, - 9.582E-6, - 1.1525E-5, - 9.052E-6, - 8.89E-6, - 1.081E-5, - 8.859E-6, - 1.05E-5, - 9.651E-6, - 7.777E-6, - 7.331E-6, - 8.23E-6, - 7.908E-6, - 8.341E-6, - 8.63E-6, - 8.275E-6, - 9.55E-6, - 8.395E-6, - 8.499E-6, - 1.2254E-5, - 7.798E-6, - 8.514E-6 - ], - [ - 9.93E-6, - 1.0113E-5, - 9.133E-6, - 9.49E-6, - 8.946E-6, - 1.1474E-5, - 9.196E-6, - 9.428E-6, - 8.952E-6, - 8.389E-6, - 9.304E-6, - 9.877E-6, - 9.181E-6, - 8.739E-6, - 1.113E-5, - 8.816E-6, - 8.981E-6, - 1.3894E-5, - 8.781E-6, - 8.725E-6, - 1.0912E-5, - 7.88E-6, - 9.389E-6, - 9.939E-6, - 8.142E-6, - 8.113E-6, - 8.033E-6, - 7.261E-6, - 6.484E-6, - 6.646E-6, - 6.392E-6, - 6.556E-6, - 6.396E-6, - 7.767E-6, - 9.403E-6, - 7.771E-6, - 7.841E-6, - 1.1258E-5, - 7.149E-6, - 7.789E-6 - ], - [ - 1.1581E-5, - 1.0122E-5, - 9.561E-6, - 9.67E-6, - 1.124E-5, - 9.248E-6, - 9.496E-6, - 9.191E-6, - 8.541E-6, - 8.252E-6, - 8.918E-6, - 9.422E-6, - 9.919E-6, - 1.1713E-5, - 9.335E-6, - 8.968E-6, - 9.754E-6, - 1.298E-5, - 1.0346E-5, - 9.16E-6, - 1.2202E-5, - 8.557E-6, - 1.1102E-5, - 9.505E-6, - 9.211E-6, - 8.307E-6, - 7.795E-6, - 7.46E-6, - 7.291E-6, - 7.867E-6, - 7.922E-6, - 7.444E-6, - 6.652E-6, - 9.276E-6, - 6.964E-6, - 6.895E-6, - 8.144E-6, - 1.1163E-5, - 7.135E-6, - 8.1E-6 - ], - [ - 1.1132E-5, - 9.059E-6, - 9.094E-6, - 8.96E-6, - 1.1023E-5, - 9.153E-6, - 8.813E-6, - 8.768E-6, - 9.004E-6, - 8.685E-6, - 8.638E-6, - 9.696E-6, - 9.098E-6, - 1.0794E-5, - 9.034E-6, - 9.098E-6, - 8.638E-6, - 2.3767E-5, - 8.245E-6, - 8.031E-6, - 1.131E-5, - 9.129E-6, - 9.896E-6, - 7.941E-6, - 8.402E-6, - 7.52E-6, - 7.474E-6, - 7.865E-6, - 7.048E-6, - 7.877E-6, - 6.861E-6, - 6.671E-6, - 6.64E-6, - 8.652E-6, - 6.625E-6, - 6.687E-6, - 8.011E-6, - 1.1579E-5, - 7.509E-6, - 6.962E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.0312219999999994E-5, - "scoreError" : 8.267534493701422E-7, - "scoreConfidence" : [ - 9.485466550629852E-6, - 1.1138973449370136E-5 - ], - "scorePercentiles" : { - "0.0" : 6.958E-6, - "50.0" : 9.676999999999999E-6, - "90.0" : 1.27767E-5, - "95.0" : 1.4859149999999996E-5, - "99.0" : 3.110289000000002E-5, - "99.9" : 3.6256E-5, - "99.99" : 3.6256E-5, - "99.999" : 3.6256E-5, - "99.9999" : 3.6256E-5, - "100.0" : 3.6256E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.1513E-5, - 1.158E-5, - 1.2738E-5, - 1.1324E-5, - 1.1024E-5, - 1.0314E-5, - 1.2049E-5, - 9.994E-6, - 9.77E-6, - 9.718E-6, - 1.2072E-5, - 9.869E-6, - 9.583E-6, - 1.1593E-5, - 1.0687E-5, - 8.549E-6, - 1.1297E-5, - 1.6101E-5, - 9.475E-6, - 8.494E-6, - 8.142E-6, - 8.801E-6, - 8.547E-6, - 8.249E-6, - 8.666E-6, - 8.036E-6, - 1.1453E-5, - 8.74E-6, - 8.449E-6, - 7.813E-6, - 7.979E-6, - 1.4672E-5, - 8.504E-6, - 1.3733E-5, - 8.458E-6, - 7.188E-6, - 8.136E-6, - 1.2424E-5, - 8.008E-6, - 7.866E-6 - ], - [ - 1.1663E-5, - 9.914E-6, - 1.0249E-5, - 1.0391E-5, - 1.2078E-5, - 1.074E-5, - 1.0071E-5, - 1.0131E-5, - 1.2167E-5, - 9.196E-6, - 9.637E-6, - 9.445E-6, - 9.605E-6, - 1.1862E-5, - 9.556E-6, - 9.472E-6, - 1.0887E-5, - 1.6005E-5, - 9.181E-6, - 8.589E-6, - 8.429E-6, - 9.964E-6, - 8.366E-6, - 8.465E-6, - 8.281E-6, - 8.489E-6, - 1.2274E-5, - 8.272E-6, - 8.242E-6, - 7.993E-6, - 8.726E-6, - 1.7282E-5, - 1.4266E-5, - 8.111E-6, - 8.074E-6, - 8.501E-6, - 8.327E-6, - 1.2781E-5, - 8.046E-6, - 7.205E-6 - ], - [ - 1.0594E-5, - 1.0602E-5, - 1.1151E-5, - 1.0725E-5, - 1.0226E-5, - 9.848E-6, - 1.0273E-5, - 1.0781E-5, - 1.01E-5, - 9.737E-6, - 9.896E-6, - 1.0044E-5, - 9.563E-6, - 1.271E-5, - 1.0142E-5, - 8.452E-6, - 9.93E-6, - 3.1127E-5, - 2.4219E-5, - 8.514E-6, - 8.502E-6, - 8.434E-6, - 8.297E-6, - 8.676E-6, - 7.741E-6, - 8.407E-6, - 1.2601E-5, - 8.245E-6, - 7.77E-6, - 8.205E-6, - 7.714E-6, - 3.6256E-5, - 8.23E-6, - 1.3686E-5, - 8.171E-6, - 6.958E-6, - 8.304E-6, - 1.2727E-5, - 7.706E-6, - 7.684E-6 - ], - [ - 1.187E-5, - 1.1117E-5, - 1.0839E-5, - 1.0092E-5, - 1.0298E-5, - 1.0152E-5, - 1.0277E-5, - 9.636E-6, - 9.725E-6, - 1.0413E-5, - 1.0307E-5, - 1.0587E-5, - 9.717E-6, - 1.3259E-5, - 8.652E-6, - 8.337E-6, - 1.0417E-5, - 1.4869E-5, - 1.1492E-5, - 8.532E-6, - 9.344E-6, - 8.102E-6, - 9.096E-6, - 8.569E-6, - 8.335E-6, - 8.705E-6, - 1.2063E-5, - 8.527E-6, - 8.568E-6, - 7.832E-6, - 8.408E-6, - 1.6453E-5, - 8.891E-6, - 1.3782E-5, - 8.091E-6, - 8.178E-6, - 8.611E-6, - 1.2121E-5, - 7.906E-6, - 8.007E-6 - ], - [ - 1.2209E-5, - 1.0556E-5, - 1.2835E-5, - 1.066E-5, - 1.0288E-5, - 1.0472E-5, - 1.0613E-5, - 9.825E-6, - 9.856E-6, - 1.0295E-5, - 1.0321E-5, - 1.0286E-5, - 9.548E-6, - 1.2951E-5, - 1.0239E-5, - 8.438E-6, - 1.0773E-5, - 2.8716E-5, - 1.0977E-5, - 1.0229E-5, - 8.65E-6, - 8.304E-6, - 8.027E-6, - 8.564E-6, - 8.202E-6, - 8.498E-6, - 1.2563E-5, - 8.46E-6, - 8.042E-6, - 8.353E-6, - 8.668E-6, - 1.7366E-5, - 8.231E-6, - 1.3029E-5, - 7.152E-6, - 8.245E-6, - 8.56E-6, - 1.1558E-5, - 8.062E-6, - 8.157E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 1.3031209999999994E-5, - "scoreError" : 8.839573714000302E-7, - "scoreConfidence" : [ - 1.2147252628599964E-5, - 1.3915167371400024E-5 - ], - "scorePercentiles" : { - "0.0" : 8.203E-6, - "50.0" : 1.21425E-5, - "90.0" : 1.81526E-5, - "95.0" : 2.1064299999999987E-5, - "99.0" : 2.440447E-5, - "99.9" : 2.4566E-5, - "99.99" : 2.4566E-5, - "99.999" : 2.4566E-5, - "99.9999" : 2.4566E-5, - "100.0" : 2.4566E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.7701E-5, - 1.1699E-5, - 1.2014E-5, - 1.1548E-5, - 1.4038E-5, - 1.4886E-5, - 1.5881E-5, - 1.146E-5, - 1.1463E-5, - 1.1346E-5, - 1.0746E-5, - 1.0914E-5, - 1.1587E-5, - 1.8863E-5, - 1.1978E-5, - 1.0185E-5, - 1.1309E-5, - 9.262E-6, - 9.124E-6, - 9.331E-6, - 1.2438E-5, - 1.4078E-5, - 1.3865E-5, - 1.4558E-5, - 1.3723E-5, - 1.4404E-5, - 2.3557E-5, - 1.0411E-5, - 9.361E-6, - 9.998E-6, - 9.784E-6, - 1.6717E-5, - 1.5624E-5, - 9.708E-6, - 8.536E-6, - 9.959E-6, - 8.962E-6, - 1.428E-5, - 9.007E-6, - 1.5873E-5 - ], - [ - 1.8041E-5, - 1.2819E-5, - 1.1652E-5, - 1.1744E-5, - 1.4823E-5, - 1.4952E-5, - 1.6583E-5, - 1.2186E-5, - 1.1793E-5, - 1.1364E-5, - 2.0044E-5, - 9.636E-6, - 9.083E-6, - 2.1821E-5, - 1.1991E-5, - 2.1118E-5, - 1.9486E-5, - 1.1048E-5, - 1.0744E-5, - 9.471E-6, - 1.1353E-5, - 1.4114E-5, - 1.3409E-5, - 1.4314E-5, - 1.4267E-5, - 1.4798E-5, - 2.3343E-5, - 1.0669E-5, - 9.136E-6, - 9.09E-6, - 9.017E-6, - 1.588E-5, - 1.5669E-5, - 9.315E-6, - 8.34E-6, - 8.93E-6, - 8.685E-6, - 1.3809E-5, - 8.203E-6, - 1.5728E-5 - ], - [ - 1.845E-5, - 1.2526E-5, - 1.2513E-5, - 1.2933E-5, - 1.5615E-5, - 1.5752E-5, - 1.6849E-5, - 1.2718E-5, - 1.3193E-5, - 1.2676E-5, - 1.9199E-5, - 1.1066E-5, - 8.987E-6, - 2.1134E-5, - 1.2154E-5, - 8.878E-6, - 1.2427E-5, - 9.599E-6, - 9.156E-6, - 8.953E-6, - 1.1739E-5, - 1.4886E-5, - 1.6949E-5, - 1.489E-5, - 1.4275E-5, - 1.5618E-5, - 2.4566E-5, - 1.1709E-5, - 8.981E-6, - 8.74E-6, - 1.1851E-5, - 1.9375E-5, - 1.5406E-5, - 8.727E-6, - 8.781E-6, - 8.7E-6, - 8.263E-6, - 1.4209E-5, - 8.537E-6, - 1.5678E-5 - ], - [ - 1.9232E-5, - 1.2008E-5, - 1.1993E-5, - 1.2104E-5, - 1.7975E-5, - 1.5551E-5, - 1.6566E-5, - 1.3063E-5, - 1.1643E-5, - 1.1146E-5, - 1.9735E-5, - 9.955E-6, - 9.22E-6, - 2.1364E-5, - 1.1568E-5, - 1.2322E-5, - 1.2289E-5, - 9.873E-6, - 9.347E-6, - 8.457E-6, - 9.202E-6, - 1.6277E-5, - 1.424E-5, - 1.3797E-5, - 1.3853E-5, - 1.6402E-5, - 2.4253E-5, - 1.0871E-5, - 1.034E-5, - 1.0604E-5, - 9.664E-6, - 1.7323E-5, - 1.588E-5, - 9.792E-6, - 9.43E-6, - 1.1936E-5, - 1.0693E-5, - 1.616E-5, - 9.555E-6, - 1.688E-5 - ], - [ - 1.7725E-5, - 1.2499E-5, - 1.2218E-5, - 1.2131E-5, - 1.54E-5, - 1.6504E-5, - 1.6562E-5, - 1.3237E-5, - 1.232E-5, - 1.2309E-5, - 1.9721E-5, - 1.102E-5, - 9.1E-6, - 2.2408E-5, - 1.0961E-5, - 9.623E-6, - 1.2E-5, - 9.676E-6, - 9.806E-6, - 9.293E-6, - 9.387E-6, - 1.5296E-5, - 1.4621E-5, - 1.5034E-5, - 1.4067E-5, - 1.3953E-5, - 2.4406E-5, - 1.0681E-5, - 1.0082E-5, - 9.953E-6, - 9.756E-6, - 1.8165E-5, - 1.5343E-5, - 8.411E-6, - 8.748E-6, - 8.788E-6, - 8.804E-6, - 1.3542E-5, - 8.441E-6, - 1.6384E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 1.7532130000000003E-5, - "scoreError" : 1.1958193186467489E-6, - "scoreConfidence" : [ - 1.6336310681353254E-5, - 1.8727949318646752E-5 - ], - "scorePercentiles" : { - "0.0" : 1.0746E-5, - "50.0" : 1.77505E-5, - "90.0" : 2.24916E-5, - "95.0" : 2.72908E-5, - "99.0" : 3.354428E-5, - "99.9" : 4.8553E-5, - "99.99" : 4.8553E-5, - "99.999" : 4.8553E-5, - "99.9999" : 4.8553E-5, - "100.0" : 4.8553E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.0305E-5, - 1.9105E-5, - 1.9004E-5, - 1.5399E-5, - 1.9714E-5, - 1.7885E-5, - 1.9478E-5, - 1.4212E-5, - 1.7924E-5, - 1.5369E-5, - 2.4777E-5, - 1.7033E-5, - 1.7798E-5, - 1.2474E-5, - 1.9047E-5, - 1.2282E-5, - 1.7743E-5, - 1.8719E-5, - 1.5024E-5, - 1.7678E-5, - 1.6763E-5, - 1.7473E-5, - 1.1969E-5, - 2.9778E-5, - 1.996E-5, - 1.1451E-5, - 4.8553E-5, - 1.1291E-5, - 1.6628E-5, - 1.2264E-5, - 1.7898E-5, - 1.1253E-5, - 1.0746E-5, - 1.855E-5, - 1.3291E-5, - 1.6626E-5, - 1.2992E-5, - 1.6369E-5, - 1.2328E-5, - 1.2569E-5 - ], - [ - 2.1961E-5, - 2.0498E-5, - 1.4835E-5, - 1.9224E-5, - 3.3551E-5, - 1.4979E-5, - 1.9223E-5, - 1.7718E-5, - 1.2044E-5, - 2.3624E-5, - 1.4161E-5, - 1.8739E-5, - 1.3821E-5, - 1.8868E-5, - 1.1367E-5, - 1.9402E-5, - 1.4091E-5, - 1.2833E-5, - 1.8522E-5, - 1.2709E-5, - 2.704E-5, - 3.2312E-5, - 1.9812E-5, - 2.0853E-5, - 1.8535E-5, - 1.9354E-5, - 1.8393E-5, - 1.8784E-5, - 1.3046E-5, - 1.8715E-5, - 1.2055E-5, - 1.1652E-5, - 1.7463E-5, - 1.2338E-5, - 1.7967E-5, - 1.1218E-5, - 1.8738E-5, - 1.258E-5, - 1.2703E-5, - 1.755E-5 - ], - [ - 2.0854E-5, - 2.0375E-5, - 1.8077E-5, - 2.0268E-5, - 2.0678E-5, - 1.6746E-5, - 2.1464E-5, - 1.6583E-5, - 1.7724E-5, - 1.6638E-5, - 2.5192E-5, - 1.3111E-5, - 1.42E-5, - 1.8642E-5, - 1.9203E-5, - 1.8283E-5, - 1.5303E-5, - 1.8525E-5, - 1.3203E-5, - 1.9368E-5, - 1.8474E-5, - 1.3311E-5, - 1.8885E-5, - 1.8896E-5, - 3.1831E-5, - 1.2299E-5, - 3.2879E-5, - 1.168E-5, - 1.0983E-5, - 1.7881E-5, - 1.6021E-5, - 1.7758E-5, - 1.2961E-5, - 1.849E-5, - 1.2843E-5, - 1.3996E-5, - 1.7565E-5, - 1.3715E-5, - 1.7292E-5, - 1.2063E-5 - ], - [ - 2.2105E-5, - 1.9375E-5, - 1.4141E-5, - 2.208E-5, - 1.8335E-5, - 1.518E-5, - 2.0287E-5, - 1.7282E-5, - 1.9898E-5, - 1.7155E-5, - 1.4924E-5, - 1.9789E-5, - 1.2374E-5, - 1.9818E-5, - 1.459E-5, - 1.9022E-5, - 1.3612E-5, - 1.2619E-5, - 1.8861E-5, - 1.6878E-5, - 2.7304E-5, - 1.3258E-5, - 1.8716E-5, - 2.4441E-5, - 2.2849E-5, - 1.8338E-5, - 2.6444E-5, - 1.7943E-5, - 1.1324E-5, - 1.8109E-5, - 1.1837E-5, - 1.217E-5, - 1.6849E-5, - 1.2167E-5, - 1.7939E-5, - 1.1703E-5, - 1.8008E-5, - 2.7648E-5, - 1.7262E-5, - 1.1975E-5 - ], - [ - 2.2516E-5, - 2.2272E-5, - 2.2534E-5, - 1.8038E-5, - 2.0077E-5, - 2.1546E-5, - 1.5422E-5, - 2.1843E-5, - 1.2691E-5, - 2.6435E-5, - 1.5268E-5, - 1.9946E-5, - 1.2724E-5, - 1.8577E-5, - 1.4354E-5, - 1.2928E-5, - 1.9172E-5, - 1.2862E-5, - 1.896E-5, - 1.2351E-5, - 2.7411E-5, - 1.2093E-5, - 1.1757E-5, - 3.2641E-5, - 1.8696E-5, - 1.9098E-5, - 1.968E-5, - 1.8298E-5, - 1.3455E-5, - 1.1636E-5, - 1.866E-5, - 1.2936E-5, - 1.7517E-5, - 1.2136E-5, - 1.911E-5, - 1.4028E-5, - 1.2447E-5, - 1.8216E-5, - 1.5333E-5, - 1.8893E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1144723499999989E-4, - "scoreError" : 1.1058793358501485E-5, - "scoreConfidence" : [ - 1.0038844164149841E-4, - 1.2250602835850137E-4 - ], - "scorePercentiles" : { - "0.0" : 5.7016E-5, - "50.0" : 1.45703E-4, - "90.0" : 1.597454E-4, - "95.0" : 1.6436925E-4, - "99.0" : 1.7420876000000002E-4, - "99.9" : 2.07914E-4, - "99.99" : 2.07914E-4, - "99.999" : 2.07914E-4, - "99.9999" : 2.07914E-4, - "100.0" : 2.07914E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.72304E-4, - 1.67911E-4, - 1.55196E-4, - 1.53195E-4, - 1.60621E-4, - 1.55215E-4, - 1.55227E-4, - 1.56133E-4, - 1.5369E-4, - 1.59786E-4, - 1.55942E-4, - 1.56158E-4, - 1.56785E-4, - 1.56749E-4, - 1.6172E-4, - 1.55615E-4, - 1.55021E-4, - 1.55684E-4, - 1.60043E-4, - 1.61992E-4, - 7.0253E-5, - 6.3163E-5, - 5.9484E-5, - 5.9629E-5, - 6.3695E-5, - 6.1474E-5, - 5.9301E-5, - 5.992E-5, - 6.3813E-5, - 6.4601E-5, - 6.1235E-5, - 5.7016E-5, - 6.0039E-5, - 6.0477E-5, - 5.9862E-5, - 6.5156E-5, - 6.2693E-5, - 6.7376E-5, - 6.1506E-5, - 6.4506E-5 - ], - [ - 1.74228E-4, - 1.64414E-4, - 1.56095E-4, - 1.51202E-4, - 1.5938E-4, - 1.50959E-4, - 1.51477E-4, - 1.5426E-4, - 1.5339E-4, - 1.54813E-4, - 1.54039E-4, - 1.55465E-4, - 1.56357E-4, - 1.51921E-4, - 1.56928E-4, - 1.54485E-4, - 1.58881E-4, - 1.52511E-4, - 1.55134E-4, - 1.57349E-4, - 1.40447E-4, - 6.411E-5, - 5.9396E-5, - 6.2892E-5, - 6.5923E-5, - 6.3789E-5, - 6.2649E-5, - 6.1297E-5, - 6.338E-5, - 6.4422E-5, - 6.9216E-5, - 7.026E-5, - 6.8288E-5, - 7.6116E-5, - 6.1955E-5, - 6.5637E-5, - 6.1686E-5, - 6.8285E-5, - 7.2524E-5, - 6.4846E-5 - ], - [ - 1.7067E-4, - 1.65651E-4, - 1.52661E-4, - 1.50977E-4, - 1.53092E-4, - 1.53146E-4, - 1.51284E-4, - 1.55318E-4, - 1.53782E-4, - 1.51287E-4, - 1.61462E-4, - 1.53462E-4, - 1.5406E-4, - 1.55853E-4, - 1.54704E-4, - 1.53947E-4, - 1.52416E-4, - 1.51976E-4, - 1.55539E-4, - 1.58258E-4, - 1.10125E-4, - 6.5484E-5, - 5.9492E-5, - 5.8506E-5, - 6.1445E-5, - 6.0726E-5, - 6.0171E-5, - 5.8945E-5, - 6.5792E-5, - 5.9667E-5, - 6.6712E-5, - 5.818E-5, - 6.6583E-5, - 5.9511E-5, - 5.9473E-5, - 6.32E-5, - 5.9153E-5, - 6.4371E-5, - 5.9452E-5, - 6.1028E-5 - ], - [ - 1.68734E-4, - 1.71234E-4, - 1.53154E-4, - 1.54617E-4, - 1.54028E-4, - 1.57453E-4, - 1.53551E-4, - 1.55169E-4, - 1.54088E-4, - 1.53981E-4, - 1.53111E-4, - 1.59078E-4, - 1.60794E-4, - 1.55266E-4, - 1.52786E-4, - 1.55195E-4, - 1.5476E-4, - 1.59012E-4, - 1.52918E-4, - 1.54E-4, - 1.13562E-4, - 6.7098E-5, - 6.1534E-5, - 5.8947E-5, - 5.9787E-5, - 6.5946E-5, - 6.677E-5, - 5.9298E-5, - 5.9656E-5, - 5.9555E-5, - 6.5343E-5, - 5.8898E-5, - 6.3709E-5, - 5.9689E-5, - 5.9902E-5, - 6.2573E-5, - 6.3671E-5, - 6.5813E-5, - 6.1154E-5, - 6.2908E-5 - ], - [ - 1.67636E-4, - 1.63519E-4, - 1.56595E-4, - 1.62045E-4, - 1.5114E-4, - 1.52722E-4, - 1.52159E-4, - 1.53283E-4, - 1.5202E-4, - 1.50965E-4, - 1.52861E-4, - 1.51466E-4, - 1.535E-4, - 1.52793E-4, - 1.58481E-4, - 1.51922E-4, - 1.51959E-4, - 2.07914E-4, - 1.53874E-4, - 1.62573E-4, - 1.06989E-4, - 1.20139E-4, - 5.8099E-5, - 6.3582E-5, - 5.7902E-5, - 9.0699E-5, - 6.5559E-5, - 6.0289E-5, - 6.7203E-5, - 5.9788E-5, - 6.1242E-5, - 6.2963E-5, - 5.8111E-5, - 6.011E-5, - 6.3339E-5, - 6.539E-5, - 5.7328E-5, - 9.2792E-5, - 5.943E-5, - 6.2171E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 2.55179115E-4, - "scoreError" : 3.1801450215650774E-5, - "scoreConfidence" : [ - 2.2337766478434923E-4, - 2.8698056521565075E-4 - ], - "scorePercentiles" : { - "0.0" : 1.63584E-4, - "50.0" : 1.73804E-4, - "90.0" : 4.875742E-4, - "95.0" : 4.9233455E-4, - "99.0" : 5.054576800000001E-4, - "99.9" : 5.18162E-4, - "99.99" : 5.18162E-4, - "99.999" : 5.18162E-4, - "99.9999" : 5.18162E-4, - "100.0" : 5.18162E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.69814E-4, - 4.66001E-4, - 4.90263E-4, - 4.83266E-4, - 4.77248E-4, - 4.75294E-4, - 5.18162E-4, - 4.82859E-4, - 4.82676E-4, - 4.94289E-4, - 3.38816E-4, - 2.9707E-4, - 1.89404E-4, - 1.7874E-4, - 1.74514E-4, - 1.73767E-4, - 1.76197E-4, - 1.79912E-4, - 1.85214E-4, - 2.01282E-4, - 1.9707E-4, - 1.96374E-4, - 2.01486E-4, - 2.00322E-4, - 2.05622E-4, - 2.04221E-4, - 2.10117E-4, - 1.94349E-4, - 1.92845E-4, - 1.91404E-4, - 1.98886E-4, - 1.92362E-4, - 2.35001E-4, - 1.83801E-4, - 1.63637E-4, - 1.64196E-4, - 1.64627E-4, - 1.68615E-4, - 1.64896E-4, - 1.63584E-4 - ], - [ - 4.70961E-4, - 4.73608E-4, - 4.89021E-4, - 4.92405E-4, - 4.81514E-4, - 4.81305E-4, - 4.79127E-4, - 4.90761E-4, - 4.80958E-4, - 4.82943E-4, - 1.83919E-4, - 1.72683E-4, - 1.70773E-4, - 1.70708E-4, - 2.07872E-4, - 1.67075E-4, - 1.68207E-4, - 1.69573E-4, - 1.67872E-4, - 1.67649E-4, - 1.73841E-4, - 1.68009E-4, - 1.66324E-4, - 1.69324E-4, - 1.72411E-4, - 1.69353E-4, - 1.67896E-4, - 1.67347E-4, - 1.79782E-4, - 1.68463E-4, - 1.68493E-4, - 1.67867E-4, - 1.82353E-4, - 1.68972E-4, - 1.6794E-4, - 1.68081E-4, - 1.65634E-4, - 1.73629E-4, - 1.67111E-4, - 1.66074E-4 - ], - [ - 4.79347E-4, - 4.81852E-4, - 4.86665E-4, - 4.90996E-4, - 4.82579E-4, - 4.77953E-4, - 4.79949E-4, - 4.82669E-4, - 4.92498E-4, - 4.7828E-4, - 2.4163E-4, - 1.71169E-4, - 1.68482E-4, - 1.9724E-4, - 1.67666E-4, - 1.66023E-4, - 1.69169E-4, - 1.67253E-4, - 1.66721E-4, - 1.69939E-4, - 1.725E-4, - 1.66913E-4, - 1.6588E-4, - 1.6566E-4, - 1.68495E-4, - 1.67994E-4, - 1.68789E-4, - 1.67576E-4, - 1.68139E-4, - 1.72393E-4, - 1.69919E-4, - 1.68377E-4, - 1.84671E-4, - 1.67739E-4, - 1.66777E-4, - 1.67156E-4, - 1.67266E-4, - 1.76223E-4, - 1.67388E-4, - 1.67255E-4 - ], - [ - 4.78435E-4, - 4.74247E-4, - 4.78663E-4, - 4.89756E-4, - 4.86712E-4, - 4.90375E-4, - 4.81261E-4, - 4.88117E-4, - 4.8767E-4, - 4.82233E-4, - 2.22277E-4, - 1.71539E-4, - 1.69622E-4, - 1.70652E-4, - 1.70406E-4, - 1.67369E-4, - 1.68473E-4, - 1.68708E-4, - 1.69104E-4, - 1.68687E-4, - 1.71794E-4, - 1.66954E-4, - 1.69363E-4, - 1.67856E-4, - 1.80825E-4, - 1.69824E-4, - 1.69472E-4, - 1.67282E-4, - 1.6959E-4, - 1.67191E-4, - 1.66411E-4, - 1.8128E-4, - 1.81413E-4, - 1.69638E-4, - 1.71267E-4, - 1.68301E-4, - 1.66623E-4, - 1.73987E-4, - 1.68168E-4, - 1.6645E-4 - ], - [ - 4.77783E-4, - 4.89708E-4, - 4.98561E-4, - 4.89785E-4, - 4.99858E-4, - 5.0551E-4, - 4.81543E-4, - 4.94473E-4, - 5.00278E-4, - 4.94226E-4, - 2.31001E-4, - 1.75226E-4, - 1.70128E-4, - 2.11101E-4, - 1.69455E-4, - 1.69622E-4, - 1.69364E-4, - 1.69646E-4, - 1.69039E-4, - 1.7109E-4, - 2.17562E-4, - 1.6694E-4, - 1.69472E-4, - 1.68692E-4, - 1.69388E-4, - 1.72158E-4, - 1.67787E-4, - 1.70844E-4, - 1.67531E-4, - 1.696E-4, - 1.81916E-4, - 1.70215E-4, - 1.95457E-4, - 1.81038E-4, - 1.76022E-4, - 1.74252E-4, - 1.94783E-4, - 2.06366E-4, - 1.90443E-4, - 1.88734E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0025111448600000008, - "scoreError" : 3.413240734944437E-4, - "scoreConfidence" : [ - 0.002169820786505557, - 0.0028524689334944444 - ], - "scorePercentiles" : { - "0.0" : 0.001533834, - "50.0" : 0.0015960599999999998, - "90.0" : 0.004735151, - "95.0" : 0.0047711137, - "99.0" : 0.005409003780000005, - "99.9" : 0.007415289, - "99.99" : 0.007415289, - "99.999" : 0.007415289, - "99.9999" : 0.007415289, - "100.0" : 0.007415289 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001606733, - 0.004668471, - 0.004689762, - 0.001578157, - 0.001578219, - 0.001572034, - 0.001605855, - 0.001614956, - 0.001586255, - 0.001582068, - 0.001573246, - 0.001595203, - 0.004719663, - 0.004745299, - 0.004619791, - 0.004568319, - 0.001583052, - 0.00154875, - 0.001543738, - 0.001711218, - 0.001588839, - 0.001534018, - 0.001533834, - 0.001539024, - 0.001540677, - 0.001568416, - 0.001546305, - 0.001571916, - 0.001587221, - 0.001575262, - 0.0015771, - 0.001582438, - 0.001599251, - 0.001600072, - 0.002736418, - 0.00472825, - 0.004720962, - 0.00477169, - 0.004743895, - 0.004761516 - ], - [ - 0.001601144, - 0.004705643, - 0.004720799, - 0.001582594, - 0.001579686, - 0.00157747, - 0.001574876, - 0.001615191, - 0.001599481, - 0.001581197, - 0.001611557, - 0.001595867, - 0.004721589, - 0.0047705, - 0.00472395, - 0.004735522, - 0.001611829, - 0.001581148, - 0.001599294, - 0.001600055, - 0.00160255, - 0.001578724, - 0.001570322, - 0.001557443, - 0.0015404, - 0.001580706, - 0.001549512, - 0.00154161, - 0.001545848, - 0.001543452, - 0.001543932, - 0.001544103, - 0.001541606, - 0.001541332, - 0.002699202, - 0.004634181, - 0.004603522, - 0.004643915, - 0.00467205, - 0.004754974 - ], - [ - 0.001568945, - 0.004624836, - 0.004687159, - 0.001554116, - 0.001601489, - 0.001550261, - 0.001603436, - 0.00161326, - 0.001586279, - 0.001579238, - 0.001583683, - 0.001613788, - 0.004771146, - 0.004822154, - 0.004694494, - 0.00469159, - 0.001610654, - 0.001578352, - 0.001536564, - 0.001554347, - 0.001591453, - 0.001541334, - 0.001559631, - 0.001542248, - 0.001539038, - 0.001580713, - 0.00153994, - 0.002033616, - 0.00154284, - 0.001828756, - 0.00154439, - 0.001555188, - 0.001540213, - 0.001537399, - 0.002636448, - 0.004672907, - 0.004743641, - 0.004737168, - 0.004796059, - 0.00491616 - ], - [ - 0.001601446, - 0.004759075, - 0.007415289, - 0.002134026, - 0.001589728, - 0.001578225, - 0.001584776, - 0.001616313, - 0.001585174, - 0.001603429, - 0.001563601, - 0.001601965, - 0.004713263, - 0.004727506, - 0.004731812, - 0.004687223, - 0.001620178, - 0.001594548, - 0.001573887, - 0.001587389, - 0.001572911, - 0.001571173, - 0.001571445, - 0.00158127, - 0.001574942, - 0.001624171, - 0.001606328, - 0.001597723, - 0.001582975, - 0.001571619, - 0.001573502, - 0.001578201, - 0.001576189, - 0.001591389, - 0.003353914, - 0.004677412, - 0.00471393, - 0.004808844, - 0.00487805, - 0.005413982 - ], - [ - 0.001621912, - 0.004652049, - 0.004705901, - 0.001590531, - 0.001589109, - 0.00157325, - 0.00159001, - 0.001616484, - 0.001621392, - 0.001607012, - 0.001574148, - 0.001596767, - 0.004717198, - 0.004687621, - 0.004711427, - 0.004697882, - 0.00160378, - 0.001583252, - 0.001588393, - 0.001588235, - 0.001581598, - 0.001568512, - 0.001590737, - 0.001596253, - 0.001580081, - 0.001617834, - 0.001584403, - 0.001584483, - 0.001595291, - 0.001578295, - 0.001590058, - 0.00161959, - 0.001582825, - 0.002177614, - 0.004718055, - 0.004722744, - 0.004767414, - 0.00471165, - 0.004804816, - 0.004669941 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.01842779793499999, - "scoreError" : 0.001762047444700974, - "scoreConfidence" : [ - 0.016665750490299017, - 0.020189845379700963 - ], - "scorePercentiles" : { - "0.0" : 0.014879851, - "50.0" : 0.015533652, - "90.0" : 0.0216740172, - "95.0" : 0.04443578139999993, - "99.0" : 0.04697062417, - "99.9" : 0.047708844, - "99.99" : 0.047708844, - "99.999" : 0.047708844, - "99.9999" : 0.047708844, - "100.0" : 0.047708844 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.019715242, - 0.016262469, - 0.015898438, - 0.044736588, - 0.021109665, - 0.015231639, - 0.016199602, - 0.038591326, - 0.015544384, - 0.015249318, - 0.015430339, - 0.046972515, - 0.020255935, - 0.015457, - 0.015290209, - 0.016832884, - 0.022143258, - 0.015182579, - 0.015158036, - 0.015150406, - 0.015393553, - 0.02127114, - 0.015441777, - 0.015030968, - 0.015980989, - 0.015309038, - 0.015164094, - 0.01549493, - 0.015638461, - 0.015387764, - 0.022582533, - 0.015982421, - 0.015397968, - 0.015242642, - 0.015082663, - 0.038720456, - 0.015176836, - 0.015541561, - 0.015806165, - 0.015391163 - ], - [ - 0.019213233, - 0.015195522, - 0.015177655, - 0.046783432, - 0.021161785, - 0.015463449, - 0.017045831, - 0.034617162, - 0.015594621, - 0.015312445, - 0.017553194, - 0.04632445, - 0.0196296, - 0.015081282, - 0.015313376, - 0.016447151, - 0.021678178, - 0.015341918, - 0.015255193, - 0.015968863, - 0.015660955, - 0.021258483, - 0.015577509, - 0.01526688, - 0.015495193, - 0.01545285, - 0.015125996, - 0.015279208, - 0.015314566, - 0.01522762, - 0.02037686, - 0.015775232, - 0.015488139, - 0.015354816, - 0.015156306, - 0.021076139, - 0.015395694, - 0.01555339, - 0.01529134, - 0.015296001 - ], - [ - 0.019592638, - 0.015238246, - 0.015329181, - 0.045512597, - 0.02140102, - 0.015219329, - 0.016337343, - 0.036605119, - 0.015391838, - 0.015248626, - 0.015542861, - 0.045028004, - 0.020059904, - 0.016019962, - 0.015427614, - 0.017071832, - 0.020319731, - 0.015232384, - 0.015259331, - 0.015942386, - 0.015525743, - 0.015913033, - 0.015420185, - 0.015106084, - 0.015115159, - 0.015690638, - 0.016046806, - 0.015863496, - 0.01577689, - 0.01536436, - 0.02163657, - 0.015382715, - 0.015585163, - 0.014966764, - 0.014999291, - 0.014923374, - 0.0154487, - 0.015640759, - 0.015409534, - 0.015542755 - ], - [ - 0.019310537, - 0.015430374, - 0.015640914, - 0.045640089, - 0.021222739, - 0.015141192, - 0.016010943, - 0.033801735, - 0.015423721, - 0.015090101, - 0.015581642, - 0.046159284, - 0.020032631, - 0.01547753, - 0.015045585, - 0.016564397, - 0.020553577, - 0.015341819, - 0.015926177, - 0.015221855, - 0.015316898, - 0.015490555, - 0.015283564, - 0.015182818, - 0.015210287, - 0.015729992, - 0.016114304, - 0.015927454, - 0.015702963, - 0.015208285, - 0.021909728, - 0.015386038, - 0.019458675, - 0.016814371, - 0.015616497, - 0.014879851, - 0.015287016, - 0.016456219, - 0.01529192, - 0.015315094 - ], - [ - 0.019155198, - 0.015568396, - 0.016132828, - 0.047708844, - 0.021210017, - 0.015267597, - 0.016349676, - 0.036018824, - 0.01512888, - 0.01535029, - 0.015919348, - 0.045472057, - 0.019420036, - 0.015308105, - 0.015291027, - 0.017118402, - 0.020772175, - 0.015617184, - 0.015412754, - 0.015359281, - 0.015200059, - 0.015470744, - 0.015502219, - 0.015305056, - 0.015132738, - 0.016374836, - 0.016368097, - 0.015396714, - 0.015515947, - 0.015394844, - 0.020679651, - 0.015144463, - 0.01545266, - 0.015388377, - 0.015675925, - 0.014981293, - 0.015200143, - 0.015560107, - 0.015546011, - 0.015320977 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1945109499999994E-4, - "scoreError" : 4.248637046125932E-6, - "scoreConfidence" : [ - 1.15202457953874E-4, - 1.2369973204612588E-4 - ], - "scorePercentiles" : { - "0.0" : 1.11062E-4, - "50.0" : 1.15004E-4, - "90.0" : 1.28183E-4, - "95.0" : 1.4650589999999988E-4, - "99.0" : 2.4359480000000024E-4, - "99.9" : 2.4919E-4, - "99.99" : 2.4919E-4, - "99.999" : 2.4919E-4, - "99.9999" : 2.4919E-4, - "100.0" : 2.4919E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.28441E-4, - 1.25861E-4, - 1.14082E-4, - 1.14078E-4, - 1.11775E-4, - 1.20328E-4, - 1.1627E-4, - 1.13987E-4, - 1.11973E-4, - 1.16889E-4, - 1.14472E-4, - 1.13196E-4, - 1.18362E-4, - 1.20518E-4, - 1.14462E-4, - 1.12581E-4, - 1.132E-4, - 1.12517E-4, - 1.19686E-4, - 1.15904E-4, - 1.12651E-4, - 1.15083E-4, - 1.12763E-4, - 1.13846E-4, - 1.14166E-4, - 1.12258E-4, - 2.4919E-4, - 1.12338E-4, - 1.49785E-4, - 1.1266E-4, - 1.36282E-4, - 1.49348E-4, - 1.13312E-4, - 1.11842E-4, - 1.13452E-4, - 1.1202E-4, - 1.22234E-4, - 1.1666E-4, - 1.16645E-4, - 1.16424E-4 - ], - [ - 1.31012E-4, - 1.22621E-4, - 1.12085E-4, - 1.13548E-4, - 1.12025E-4, - 1.18983E-4, - 1.14035E-4, - 1.13266E-4, - 1.14386E-4, - 1.14522E-4, - 1.13665E-4, - 1.11838E-4, - 1.14663E-4, - 1.12898E-4, - 1.11989E-4, - 1.16904E-4, - 1.11896E-4, - 1.12955E-4, - 1.12901E-4, - 1.12588E-4, - 1.11927E-4, - 1.16011E-4, - 1.15946E-4, - 1.12593E-4, - 1.1466E-4, - 1.16718E-4, - 1.17772E-4, - 1.12702E-4, - 1.15023E-4, - 1.14194E-4, - 1.19849E-4, - 1.20717E-4, - 1.12553E-4, - 1.12553E-4, - 1.1303E-4, - 1.16869E-4, - 1.17187E-4, - 1.14603E-4, - 1.15199E-4, - 1.17736E-4 - ], - [ - 1.33692E-4, - 1.22601E-4, - 1.14912E-4, - 1.13942E-4, - 1.13615E-4, - 1.15213E-4, - 1.15624E-4, - 1.15942E-4, - 1.12152E-4, - 1.14096E-4, - 1.11908E-4, - 1.12333E-4, - 1.16662E-4, - 1.1346E-4, - 1.12671E-4, - 1.13163E-4, - 1.18387E-4, - 1.18417E-4, - 1.12483E-4, - 1.14786E-4, - 1.12839E-4, - 1.13588E-4, - 1.11707E-4, - 1.12395E-4, - 1.13599E-4, - 1.15276E-4, - 2.15954E-4, - 1.14606E-4, - 1.31619E-4, - 1.1462E-4, - 1.18439E-4, - 2.05213E-4, - 1.17625E-4, - 1.14597E-4, - 1.14075E-4, - 1.12E-4, - 1.16725E-4, - 1.16922E-4, - 1.13214E-4, - 1.47044E-4 - ], - [ - 1.3184E-4, - 1.30622E-4, - 1.14128E-4, - 1.19215E-4, - 1.16979E-4, - 1.15385E-4, - 1.18962E-4, - 1.16605E-4, - 1.17861E-4, - 1.15574E-4, - 1.11883E-4, - 1.15425E-4, - 1.2091E-4, - 1.14322E-4, - 1.17386E-4, - 1.1508E-4, - 1.16107E-4, - 1.14068E-4, - 1.18263E-4, - 1.13638E-4, - 1.11924E-4, - 1.16643E-4, - 1.16718E-4, - 1.16807E-4, - 1.1349E-4, - 1.16919E-4, - 2.43874E-4, - 1.14857E-4, - 1.565E-4, - 1.19295E-4, - 1.13557E-4, - 1.85017E-4, - 1.14294E-4, - 1.15751E-4, - 1.12195E-4, - 1.12189E-4, - 1.16329E-4, - 1.2325E-4, - 1.16011E-4, - 1.15357E-4 - ], - [ - 1.28458E-4, - 1.34164E-4, - 1.12749E-4, - 1.14419E-4, - 1.11668E-4, - 1.13399E-4, - 1.17476E-4, - 1.15368E-4, - 1.15843E-4, - 1.14757E-4, - 1.11062E-4, - 1.15072E-4, - 1.14985E-4, - 1.16623E-4, - 1.14082E-4, - 1.12051E-4, - 1.18155E-4, - 1.16196E-4, - 1.11781E-4, - 1.16917E-4, - 1.16234E-4, - 1.18527E-4, - 1.13071E-4, - 1.31499E-4, - 1.17175E-4, - 1.14046E-4, - 1.16308E-4, - 1.14324E-4, - 1.18464E-4, - 1.12672E-4, - 1.13939E-4, - 1.50435E-4, - 1.15078E-4, - 1.16755E-4, - 1.18728E-4, - 1.13627E-4, - 1.17352E-4, - 1.12587E-4, - 1.14673E-4, - 1.17991E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.924638649999999E-4, - "scoreError" : 1.5392262632764065E-5, - "scoreConfidence" : [ - 1.7707160236723584E-4, - 2.0785612763276397E-4 - ], - "scorePercentiles" : { - "0.0" : 1.4645E-4, - "50.0" : 1.529845E-4, - "90.0" : 2.246841E-4, - "95.0" : 4.1552684999999904E-4, - "99.0" : 4.3108221E-4, - "99.9" : 4.33634E-4, - "99.99" : 4.33634E-4, - "99.999" : 4.33634E-4, - "99.9999" : 4.33634E-4, - "100.0" : 4.33634E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.33634E-4, - 4.2494E-4, - 2.24887E-4, - 2.17664E-4, - 2.20388E-4, - 2.14184E-4, - 2.14931E-4, - 2.22858E-4, - 2.21678E-4, - 2.21808E-4, - 2.1793E-4, - 2.16118E-4, - 2.15917E-4, - 2.21341E-4, - 2.20529E-4, - 2.26088E-4, - 2.76256E-4, - 1.54925E-4, - 1.51669E-4, - 1.53364E-4, - 1.50836E-4, - 1.51073E-4, - 1.56809E-4, - 1.509E-4, - 1.51181E-4, - 1.50864E-4, - 1.51891E-4, - 1.50041E-4, - 1.50731E-4, - 1.51156E-4, - 1.51047E-4, - 1.51181E-4, - 1.51164E-4, - 1.51131E-4, - 1.53064E-4, - 1.5131E-4, - 1.51829E-4, - 1.51748E-4, - 1.50999E-4, - 1.52264E-4 - ], - [ - 4.30509E-4, - 4.31088E-4, - 2.25501E-4, - 2.21115E-4, - 2.15446E-4, - 2.22444E-4, - 2.19883E-4, - 2.20315E-4, - 2.19017E-4, - 2.18239E-4, - 2.16508E-4, - 2.16767E-4, - 2.17822E-4, - 2.17029E-4, - 2.18181E-4, - 2.19814E-4, - 3.05731E-4, - 1.56433E-4, - 1.52905E-4, - 1.5405E-4, - 1.5197E-4, - 1.51511E-4, - 1.54897E-4, - 1.51703E-4, - 1.50501E-4, - 1.50879E-4, - 1.5231E-4, - 1.50466E-4, - 1.51541E-4, - 1.51388E-4, - 1.51212E-4, - 1.50856E-4, - 1.50873E-4, - 1.5003E-4, - 1.50461E-4, - 1.523E-4, - 1.52079E-4, - 1.51277E-4, - 1.87098E-4, - 1.52115E-4 - ], - [ - 4.2105E-4, - 4.27078E-4, - 2.25541E-4, - 2.20828E-4, - 2.22206E-4, - 2.12617E-4, - 2.17591E-4, - 2.17479E-4, - 2.13776E-4, - 2.17028E-4, - 2.14738E-4, - 2.13765E-4, - 2.18875E-4, - 2.18388E-4, - 2.14951E-4, - 2.12465E-4, - 3.05972E-4, - 1.57435E-4, - 1.52371E-4, - 1.54E-4, - 1.51993E-4, - 1.51339E-4, - 1.50864E-4, - 1.52379E-4, - 1.50738E-4, - 1.51849E-4, - 1.50727E-4, - 1.51006E-4, - 1.51283E-4, - 1.50373E-4, - 1.50402E-4, - 1.66798E-4, - 1.50966E-4, - 1.50851E-4, - 1.50586E-4, - 1.50145E-4, - 1.51848E-4, - 1.51597E-4, - 1.52343E-4, - 1.51509E-4 - ], - [ - 4.2028E-4, - 4.2232E-4, - 2.221E-4, - 2.18527E-4, - 2.18995E-4, - 2.15753E-4, - 2.14495E-4, - 2.18304E-4, - 2.12229E-4, - 2.17727E-4, - 2.18181E-4, - 2.14046E-4, - 2.14084E-4, - 2.20282E-4, - 2.18294E-4, - 2.20869E-4, - 3.01397E-4, - 1.58429E-4, - 1.52419E-4, - 1.54313E-4, - 1.52092E-4, - 1.51971E-4, - 1.50716E-4, - 1.50565E-4, - 1.51498E-4, - 1.50993E-4, - 1.51807E-4, - 1.50697E-4, - 1.52131E-4, - 1.5106E-4, - 1.51042E-4, - 1.51118E-4, - 1.51914E-4, - 1.5063E-4, - 1.51197E-4, - 1.50803E-4, - 1.52086E-4, - 1.52574E-4, - 1.5139E-4, - 1.51836E-4 - ], - [ - 4.199E-4, - 4.21169E-4, - 2.27449E-4, - 2.21039E-4, - 2.12186E-4, - 2.10767E-4, - 2.09048E-4, - 2.14919E-4, - 2.13261E-4, - 2.16644E-4, - 2.15155E-4, - 2.17899E-4, - 2.15935E-4, - 2.15655E-4, - 2.20665E-4, - 2.15339E-4, - 3.32437E-4, - 1.52502E-4, - 1.49326E-4, - 1.51792E-4, - 1.47731E-4, - 1.47449E-4, - 1.53314E-4, - 1.47112E-4, - 1.47034E-4, - 1.46734E-4, - 1.4794E-4, - 1.46937E-4, - 1.47104E-4, - 1.48377E-4, - 1.47364E-4, - 1.86805E-4, - 1.47278E-4, - 1.46781E-4, - 1.4645E-4, - 1.46513E-4, - 1.48468E-4, - 1.48901E-4, - 1.48329E-4, - 1.47559E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.002571081605, - "scoreError" : 0.0010528150851568773, - "scoreConfidence" : [ - 0.0015182665198431226, - 0.0036238966901568775 - ], - "scorePercentiles" : { - "0.0" : 0.001157877, - "50.0" : 0.0011908885, - "90.0" : 0.0018675251, - "95.0" : 0.0180821838, - "99.0" : 0.0184251219, - "99.9" : 0.018575664, - "99.99" : 0.018575664, - "99.999" : 0.018575664, - "99.9999" : 0.018575664, - "100.0" : 0.018575664 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001188078, - 0.001191262, - 0.001230655, - 0.001837945, - 0.001849608, - 0.018083927, - 0.001186499, - 0.001189172, - 0.001188895, - 0.001189416, - 0.001189389, - 0.01771084, - 0.001164439, - 0.001164031, - 0.001168695, - 0.001159943, - 0.001165228, - 0.001169185, - 0.001777501, - 0.001811485, - 0.001808443, - 0.001837083, - 0.001793541, - 0.018425185, - 0.001165735, - 0.001164132, - 0.001172833, - 0.001166353, - 0.001169515, - 0.001167233, - 0.001165456, - 0.001209669, - 0.001170588, - 0.001167185, - 0.00120385, - 0.001168708, - 0.001175402, - 0.001167981, - 0.001170859, - 0.001197912 - ], - [ - 0.001165889, - 0.001172591, - 0.001206109, - 0.001833887, - 0.001867653, - 0.018339798, - 0.001167368, - 0.001166535, - 0.001167409, - 0.001165948, - 0.001161205, - 0.018201594, - 0.001164472, - 0.001165751, - 0.001165168, - 0.001167527, - 0.001169952, - 0.001165047, - 0.001808291, - 0.001803094, - 0.001797288, - 0.001840105, - 0.001795799, - 0.018192652, - 0.001159807, - 0.001201298, - 0.00116856, - 0.001166161, - 0.001168206, - 0.001170415, - 0.001158753, - 0.001165479, - 0.001166256, - 0.001218467, - 0.001196406, - 0.001161945, - 0.001192445, - 0.00119186, - 0.001193405, - 0.001191772 - ], - [ - 0.001169327, - 0.001161232, - 0.001208152, - 0.001808193, - 0.001860676, - 0.018418875, - 0.001163875, - 0.00115817, - 0.001166192, - 0.001167505, - 0.001157877, - 0.01824885, - 0.00117062, - 0.001162399, - 0.001168353, - 0.001164236, - 0.001212095, - 0.00116488, - 0.001817892, - 0.001866374, - 0.001870828, - 0.001836517, - 0.001844997, - 0.01823695, - 0.001187311, - 0.001226774, - 0.001193187, - 0.001193558, - 0.001196195, - 0.0011864, - 0.001160859, - 0.001169405, - 0.001169073, - 0.001243814, - 0.001196924, - 0.001161564, - 0.001165597, - 0.00116375, - 0.001172462, - 0.001165386 - ], - [ - 0.001195798, - 0.001192974, - 0.001256421, - 0.001843589, - 0.001877434, - 0.018047139, - 0.001192534, - 0.001187909, - 0.001194221, - 0.001194767, - 0.001186486, - 0.01782113, - 0.001188467, - 0.001164103, - 0.001169093, - 0.001168683, - 0.001167199, - 0.001170063, - 0.001797513, - 0.001814231, - 0.001791607, - 0.001804389, - 0.001824786, - 0.018575664, - 0.001161485, - 0.001164604, - 0.001172049, - 0.001170147, - 0.001168011, - 0.001161284, - 0.001161737, - 0.001249748, - 0.001168737, - 0.001167263, - 0.001195367, - 0.001163486, - 0.001170369, - 0.001167075, - 0.001169355, - 0.001167566 - ], - [ - 0.001193088, - 0.001195988, - 0.001233901, - 0.001839296, - 0.001866032, - 0.018049063, - 0.001192319, - 0.001186831, - 0.001191494, - 0.001188183, - 0.001186944, - 0.017849051, - 0.001202051, - 0.001209072, - 0.001246946, - 0.001293249, - 0.001222799, - 0.001194139, - 0.00184582, - 0.00186113, - 0.001875978, - 0.001850583, - 0.00189348, - 0.018218331, - 0.001188109, - 0.001193858, - 0.001196885, - 0.001191407, - 0.001411511, - 0.001186684, - 0.001186729, - 0.001234516, - 0.001192172, - 0.001197548, - 0.001226317, - 0.001188741, - 0.001190515, - 0.001190242, - 0.001193323, - 0.001193966 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.018934058250000007, - "scoreError" : 0.007464157084038221, - "scoreConfidence" : [ - 0.011469901165961787, - 0.026398215334038227 - ], - "scorePercentiles" : { - "0.0" : 0.010043578, - "50.0" : 0.0105508255, - "90.0" : 0.0117502443, - "95.0" : 0.13731859759999998, - "99.0" : 0.14130487378, - "99.9" : 0.143638802, - "99.99" : 0.143638802, - "99.999" : 0.143638802, - "99.9999" : 0.143638802, - "100.0" : 0.143638802 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.010890662, - 0.140151972, - 0.010657398, - 0.011262281, - 0.010181611, - 0.010309932, - 0.010883881, - 0.011285999, - 0.010169471, - 0.010443645, - 0.139052778, - 0.010695463, - 0.010379092, - 0.011118059, - 0.010507199, - 0.010121987, - 0.010501209, - 0.010243036, - 0.010517823, - 0.010369009, - 0.010513457, - 0.010043578, - 0.010339599, - 0.010442173, - 0.010432139, - 0.010443254, - 0.010272965, - 0.01046462, - 0.010170369, - 0.010635188, - 0.133373539, - 0.010627301, - 0.010526895, - 0.010356594, - 0.010402861, - 0.010064688, - 0.010460305, - 0.010449581, - 0.010669285, - 0.010318169 - ], - [ - 0.010843633, - 0.139680795, - 0.010593333, - 0.010091995, - 0.010338562, - 0.011112462, - 0.010848374, - 0.010989673, - 0.010338104, - 0.01060677, - 0.14097142, - 0.01086922, - 0.010596168, - 0.010346098, - 0.010397119, - 0.010288422, - 0.010306609, - 0.010394416, - 0.01061827, - 0.010341051, - 0.010848969, - 0.132194412, - 0.010614742, - 0.010517957, - 0.010272304, - 0.010368477, - 0.010099045, - 0.010620146, - 0.010552433, - 0.010346289, - 0.010692158, - 0.010825035, - 0.010504801, - 0.010534912, - 0.010086298, - 0.010508138, - 0.01012584, - 0.010338709, - 0.010324335, - 0.010589123 - ], - [ - 0.011099876, - 0.141308242, - 0.011918732, - 0.010611027, - 0.010669855, - 0.010947354, - 0.010988497, - 0.01102686, - 0.010172363, - 0.0108023, - 0.143638802, - 0.010511751, - 0.010653828, - 0.010368099, - 0.010554757, - 0.01034625, - 0.010568067, - 0.010867928, - 0.010486898, - 0.01055273, - 0.010423856, - 0.13615579, - 0.010352563, - 0.010378211, - 0.010476463, - 0.010666208, - 0.01018948, - 0.010556796, - 0.010626531, - 0.010496947, - 0.01036796, - 0.0104094, - 0.010377237, - 0.010280531, - 0.010360107, - 0.010543471, - 0.011018736, - 0.010303659, - 0.010500283, - 0.010408966 - ], - [ - 0.010859257, - 0.139214631, - 0.010678422, - 0.010543896, - 0.010844033, - 0.011214235, - 0.010839694, - 0.010531584, - 0.010327768, - 0.010720826, - 0.13843499, - 0.010478928, - 0.010489273, - 0.010208301, - 0.010552355, - 0.010370722, - 0.010446921, - 0.01040147, - 0.010625456, - 0.011753154, - 0.014000535, - 0.137379798, - 0.011377838, - 0.010891303, - 0.011099745, - 0.010406588, - 0.010599419, - 0.010412704, - 0.010723655, - 0.010551619, - 0.010718734, - 0.01038377, - 0.011139392, - 0.011724057, - 0.012163269, - 0.010931401, - 0.012143749, - 0.012532155, - 0.010166564, - 0.012323542 - ], - [ - 0.010849279, - 0.010812317, - 0.010602696, - 0.010371685, - 0.010468987, - 0.010635896, - 0.010897843, - 0.010550032, - 0.010604142, - 0.010489492, - 0.010391517, - 0.010685929, - 0.010514689, - 0.010682262, - 0.13829516, - 0.010594125, - 0.010476497, - 0.010255843, - 0.010603466, - 0.01064522, - 0.010520216, - 0.010617019, - 0.010488072, - 0.010939101, - 0.010710177, - 0.010400433, - 0.010795933, - 0.010459709, - 0.010554849, - 0.010279635, - 0.010491318, - 0.010431794, - 0.010343304, - 0.010881872, - 0.010554362, - 0.010591141, - 0.01040035, - 0.010429605, - 0.01042451, - 0.010592325 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.9052169500000002E-4, - "scoreError" : 2.7547829291905938E-5, - "scoreConfidence" : [ - 1.629738657080941E-4, - 2.1806952429190594E-4 - ], - "scorePercentiles" : { - "0.0" : 5.3141E-5, - "50.0" : 2.11595E-4, - "90.0" : 3.72638E-4, - "95.0" : 3.766676E-4, - "99.0" : 3.8457736E-4, - "99.9" : 3.85111E-4, - "99.99" : 3.85111E-4, - "99.999" : 3.85111E-4, - "99.9999" : 3.85111E-4, - "100.0" : 3.85111E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 3.60746E-4, - 3.67177E-4, - 3.67358E-4, - 3.7108E-4, - 3.71896E-4, - 3.74889E-4, - 3.66121E-4, - 3.74577E-4, - 2.66106E-4, - 2.39226E-4, - 2.32587E-4, - 2.09297E-4, - 2.06759E-4, - 2.09003E-4, - 2.11583E-4, - 2.23038E-4, - 2.12274E-4, - 2.11821E-4, - 2.09513E-4, - 2.09596E-4, - 2.10205E-4, - 2.12298E-4, - 2.14582E-4, - 2.0699E-4, - 2.12983E-4, - 2.07753E-4, - 5.3141E-5, - 6.1188E-5, - 5.8461E-5, - 5.7467E-5, - 5.8146E-5, - 5.9758E-5, - 1.01072E-4, - 5.8105E-5, - 6.2723E-5, - 6.0051E-5, - 6.1328E-5, - 5.3637E-5, - 5.4863E-5, - 5.5791E-5 - ], - [ - 3.65172E-4, - 3.67335E-4, - 3.6833E-4, - 3.6609E-4, - 3.7262E-4, - 3.71512E-4, - 3.64787E-4, - 3.77097E-4, - 2.54396E-4, - 2.38001E-4, - 2.38525E-4, - 2.15279E-4, - 2.13404E-4, - 2.14338E-4, - 2.09323E-4, - 2.21139E-4, - 2.14328E-4, - 2.12972E-4, - 2.16617E-4, - 2.13395E-4, - 2.1268E-4, - 2.09735E-4, - 2.08471E-4, - 2.09817E-4, - 2.13448E-4, - 5.8257E-5, - 5.5265E-5, - 5.9269E-5, - 5.7324E-5, - 7.15E-5, - 5.593E-5, - 5.5758E-5, - 6.2807E-5, - 5.5827E-5, - 5.4885E-5, - 5.6901E-5, - 5.7377E-5, - 5.8372E-5, - 5.6279E-5, - 5.5838E-5 - ], - [ - 3.79694E-4, - 3.85111E-4, - 3.81636E-4, - 3.76735E-4, - 3.76065E-4, - 3.77756E-4, - 3.76009E-4, - 3.82732E-4, - 2.6535E-4, - 2.43337E-4, - 2.40984E-4, - 2.1817E-4, - 2.22207E-4, - 2.16119E-4, - 2.14129E-4, - 2.28595E-4, - 2.14333E-4, - 2.17067E-4, - 2.17253E-4, - 2.17719E-4, - 2.26893E-4, - 2.1363E-4, - 2.14247E-4, - 2.21815E-4, - 2.18884E-4, - 5.7994E-5, - 6.0388E-5, - 5.9324E-5, - 5.6329E-5, - 5.7763E-5, - 5.5829E-5, - 5.7771E-5, - 5.7835E-5, - 5.9872E-5, - 5.565E-5, - 5.6268E-5, - 5.4287E-5, - 5.5521E-5, - 5.5479E-5, - 5.7642E-5 - ], - [ - 3.72588E-4, - 3.68375E-4, - 3.66744E-4, - 3.75528E-4, - 3.76451E-4, - 3.75938E-4, - 3.68161E-4, - 3.84596E-4, - 2.58794E-4, - 2.4048E-4, - 2.35542E-4, - 2.16133E-4, - 2.107E-4, - 2.12586E-4, - 2.08138E-4, - 2.24001E-4, - 2.08348E-4, - 2.0789E-4, - 2.11577E-4, - 2.17214E-4, - 2.13768E-4, - 2.17073E-4, - 2.12514E-4, - 2.10956E-4, - 2.14312E-4, - 5.689E-5, - 6.1772E-5, - 6.0345E-5, - 5.5863E-5, - 5.4377E-5, - 5.4461E-5, - 5.6986E-5, - 5.433E-5, - 5.441E-5, - 5.9089E-5, - 6.2678E-5, - 5.6693E-5, - 5.6323E-5, - 5.7283E-5, - 6.1755E-5 - ], - [ - 3.67905E-4, - 3.77365E-4, - 3.68683E-4, - 3.76489E-4, - 3.7264E-4, - 3.69392E-4, - 3.74516E-4, - 3.76677E-4, - 2.54456E-4, - 2.36135E-4, - 2.36032E-4, - 2.08606E-4, - 2.07682E-4, - 2.11607E-4, - 2.11419E-4, - 2.17608E-4, - 2.15595E-4, - 2.10668E-4, - 2.16198E-4, - 2.18802E-4, - 2.1289E-4, - 2.12323E-4, - 2.0961E-4, - 2.08193E-4, - 2.09313E-4, - 5.3953E-5, - 5.6015E-5, - 5.5414E-5, - 6.1445E-5, - 6.3981E-5, - 5.4364E-5, - 7.7555E-5, - 5.4628E-5, - 6.0446E-5, - 6.0762E-5, - 5.7906E-5, - 5.6569E-5, - 5.6267E-5, - 6.5496E-5, - 5.7061E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 7.919515550000008E-4, - "scoreError" : 6.223901722385885E-4, - "scoreConfidence" : [ - 1.6956138276141223E-4, - 0.0014143417272385892 - ], - "scorePercentiles" : { - "0.0" : 2.37854E-4, - "50.0" : 2.578155E-4, - "90.0" : 5.924103E-4, - "95.0" : 6.104163499999999E-4, - "99.0" : 0.017180825309999998, - "99.9" : 0.017547936, - "99.99" : 0.017547936, - "99.999" : 0.017547936, - "99.9999" : 0.017547936, - "100.0" : 0.017547936 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 5.79169E-4, - 5.73815E-4, - 5.74743E-4, - 5.71308E-4, - 3.33532E-4, - 2.95759E-4, - 2.42035E-4, - 2.59563E-4, - 2.39029E-4, - 2.55591E-4, - 2.43074E-4, - 2.3994E-4, - 2.42381E-4, - 2.55361E-4, - 2.42967E-4, - 2.42919E-4, - 0.017181289, - 2.45332E-4, - 2.38902E-4, - 2.41059E-4, - 2.54968E-4, - 3.35883E-4, - 2.44177E-4, - 2.42874E-4, - 2.40738E-4, - 2.56167E-4, - 2.46552E-4, - 2.44013E-4, - 2.41284E-4, - 2.38142E-4, - 3.32196E-4, - 5.8856E-4, - 5.79742E-4, - 5.77785E-4, - 5.72692E-4, - 5.84772E-4, - 5.91827E-4, - 5.97253E-4, - 5.78537E-4, - 5.81585E-4 - ], - [ - 5.84676E-4, - 5.83998E-4, - 5.82069E-4, - 5.91896E-4, - 3.35313E-4, - 3.15796E-4, - 2.54385E-4, - 2.56324E-4, - 2.52793E-4, - 2.55798E-4, - 2.38656E-4, - 2.4034E-4, - 2.39197E-4, - 2.41397E-4, - 2.41412E-4, - 2.43419E-4, - 0.01713492, - 2.61629E-4, - 2.55213E-4, - 2.42581E-4, - 2.56337E-4, - 2.52097E-4, - 2.41571E-4, - 2.57034E-4, - 2.4335E-4, - 2.62296E-4, - 2.53328E-4, - 2.45816E-4, - 2.40263E-4, - 2.44291E-4, - 3.58803E-4, - 5.94283E-4, - 6.04265E-4, - 5.73459E-4, - 6.06395E-4, - 5.8669E-4, - 5.8452E-4, - 5.88489E-4, - 5.95837E-4, - 5.93658E-4 - ], - [ - 5.81471E-4, - 5.93994E-4, - 5.63732E-4, - 5.70232E-4, - 3.61764E-4, - 3.04608E-4, - 2.40384E-4, - 2.66735E-4, - 2.38051E-4, - 2.38728E-4, - 2.39348E-4, - 2.55107E-4, - 2.5627E-4, - 2.55601E-4, - 2.42375E-4, - 4.73984E-4, - 0.016920146, - 2.48704E-4, - 2.41457E-4, - 2.42302E-4, - 2.43827E-4, - 2.57123E-4, - 3.71763E-4, - 2.43448E-4, - 2.42364E-4, - 2.58412E-4, - 2.49123E-4, - 2.44912E-4, - 2.41301E-4, - 2.44236E-4, - 3.53793E-4, - 5.82392E-4, - 5.79367E-4, - 5.91198E-4, - 5.81489E-4, - 5.75985E-4, - 5.89827E-4, - 5.82444E-4, - 5.66644E-4, - 5.95509E-4 - ], - [ - 5.87964E-4, - 5.77984E-4, - 5.64089E-4, - 5.76472E-4, - 4.62947E-4, - 2.77819E-4, - 2.52479E-4, - 2.56731E-4, - 2.38743E-4, - 2.54736E-4, - 2.39741E-4, - 2.51926E-4, - 2.52343E-4, - 2.54767E-4, - 2.40669E-4, - 2.38177E-4, - 0.017547936, - 2.78466E-4, - 2.54636E-4, - 2.57932E-4, - 2.40724E-4, - 2.6469E-4, - 2.57699E-4, - 2.38805E-4, - 2.55282E-4, - 2.39216E-4, - 2.4741E-4, - 2.54897E-4, - 2.4191E-4, - 2.55574E-4, - 5.65289E-4, - 5.8754E-4, - 5.65922E-4, - 5.78222E-4, - 5.65458E-4, - 5.81047E-4, - 5.72746E-4, - 5.73491E-4, - 5.67877E-4, - 5.80498E-4 - ], - [ - 6.10628E-4, - 6.35885E-4, - 6.11403E-4, - 6.25235E-4, - 2.87257E-4, - 2.93135E-4, - 2.41625E-4, - 2.4161E-4, - 2.39815E-4, - 2.41357E-4, - 2.40968E-4, - 2.3845E-4, - 2.56148E-4, - 2.55064E-4, - 2.42472E-4, - 2.4123E-4, - 0.017106261, - 2.63859E-4, - 2.56698E-4, - 2.57478E-4, - 2.4088E-4, - 2.4218E-4, - 2.54247E-4, - 2.56916E-4, - 2.54826E-4, - 4.79977E-4, - 2.70194E-4, - 2.60027E-4, - 2.37854E-4, - 2.56355E-4, - 3.48245E-4, - 6.12313E-4, - 5.9344E-4, - 5.87812E-4, - 5.87461E-4, - 5.81146E-4, - 5.92457E-4, - 5.90151E-4, - 5.72149E-4, - 5.9199E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.004144344479999999, - "scoreError" : 0.003119424338248426, - "scoreConfidence" : [ - 0.001024920141751573, - 0.007263768818248426 - ], - "scorePercentiles" : { - "0.0" : 0.002206665, - "50.0" : 0.0026110465, - "90.0" : 0.0057495673, - "95.0" : 0.0065984667999999976, - "99.0" : 0.00742134581, - "99.9" : 0.18900029, - "99.99" : 0.18900029, - "99.999" : 0.18900029, - "99.9999" : 0.18900029, - "100.0" : 0.18900029 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.002262267, - 0.002628417, - 0.003681065, - 0.002385086, - 0.002244276, - 0.005750807, - 0.004345829, - 0.002275, - 0.002351713, - 0.002314392, - 0.00455161, - 0.005653723, - 0.002643549, - 0.002704678, - 0.00262816, - 0.002645288, - 0.00282946, - 0.006270428, - 0.007127719, - 0.003227388, - 0.002206788, - 0.00234738, - 0.002216778, - 0.002348509, - 0.002625198, - 0.002213632, - 0.004256462, - 0.002341972, - 0.002244304, - 0.002375673, - 0.002211398, - 0.002450263, - 0.002269248, - 0.002320633, - 0.004662205, - 0.00596484, - 0.002397389, - 0.003898681, - 0.00393618, - 0.002358217 - ], - [ - 0.002466753, - 0.002493581, - 0.003173184, - 0.002389774, - 0.002376692, - 0.00576197, - 0.00385513, - 0.002400971, - 0.00248342, - 0.00226452, - 0.003558733, - 0.005521726, - 0.002740647, - 0.00286486, - 0.002630601, - 0.002636529, - 0.002513481, - 0.005552421, - 0.006119326, - 0.00355021, - 0.002215302, - 0.002223889, - 0.002220301, - 0.002442276, - 0.002612322, - 0.002372783, - 0.004189212, - 0.002383294, - 0.002223949, - 0.002248344, - 0.002256294, - 0.002570282, - 0.002394303, - 0.002276744, - 0.003193541, - 0.006123177, - 0.002639965, - 0.003015564, - 0.004137371, - 0.002216958 - ], - [ - 0.002273392, - 0.002631759, - 0.003266557, - 0.002346596, - 0.002282935, - 0.005474676, - 0.003882156, - 0.002291541, - 0.002440547, - 0.00229346, - 0.002970206, - 0.004135194, - 0.002372888, - 0.002219801, - 0.002218448, - 0.002464727, - 0.002545079, - 0.00573841, - 0.007405289, - 0.004735203, - 0.002593267, - 0.002625808, - 0.002656078, - 0.002666458, - 0.002567444, - 0.002506541, - 0.004097112, - 0.002387042, - 0.002213812, - 0.002370082, - 0.002362104, - 0.00259431, - 0.002369572, - 0.002407316, - 0.002431526, - 0.006379336, - 0.002797721, - 0.002938148, - 0.007344875, - 0.002394328 - ], - [ - 0.002501285, - 0.002310605, - 0.003683124, - 0.002287606, - 0.002222295, - 0.005771337, - 0.003612682, - 0.002506957, - 0.00241991, - 0.002326161, - 0.002698688, - 0.18900029, - 0.002234404, - 0.002360535, - 0.00232246, - 0.002259736, - 0.002477597, - 0.005676528, - 0.00661, - 0.004600242, - 0.002561841, - 0.002801411, - 0.002642838, - 0.002528224, - 0.002561247, - 0.002297108, - 0.004165432, - 0.002385132, - 0.002206665, - 0.002381108, - 0.002986947, - 0.002822636, - 0.002534991, - 0.002634864, - 0.002550625, - 0.005710169, - 0.003011942, - 0.006866306, - 0.007123112, - 0.00245847 - ], - [ - 0.002474574, - 0.002526883, - 0.00328726, - 0.002251801, - 0.002328413, - 0.006028199, - 0.003674762, - 0.00242738, - 0.002266154, - 0.002583256, - 0.002928467, - 0.005442842, - 0.002788584, - 0.002690464, - 0.002651459, - 0.002805371, - 0.002735269, - 0.007319739, - 0.007421508, - 0.004590612, - 0.002733468, - 0.002824289, - 0.002625477, - 0.002569264, - 0.002650283, - 0.002452617, - 0.005445862, - 0.002612008, - 0.002675603, - 0.002832361, - 0.002843605, - 0.002610085, - 0.002500805, - 0.002386464, - 0.002384479, - 0.005878867, - 0.0030155, - 0.003474235, - 0.007292458, - 0.00255591 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.460003780135, - "scoreError" : 0.2372513992373334, - "scoreConfidence" : [ - 0.22275238089766658, - 0.6972551793723334 - ], - "scorePercentiles" : { - "0.0" : 0.023200632, - "50.0" : 0.0260964485, - "90.0" : 1.7662338435, - "95.0" : 2.4836163858499996, - "99.0" : 4.856327799870003, - "99.9" : 5.014103322, - "99.99" : 5.014103322, - "99.999" : 5.014103322, - "99.9999" : 5.014103322, - "100.0" : 5.014103322 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.025135005, - 0.033465488, - 0.024857311, - 0.02492689, - 0.034385502, - 0.025003503, - 1.364798848, - 2.338667653, - 1.735159095, - 0.027108967, - 0.026209806, - 0.024536683, - 0.024917452, - 0.033903174, - 0.023797908, - 0.025002536, - 0.029124043, - 4.052022169, - 1.592580669, - 0.023942734, - 0.025283336, - 0.027176785, - 0.0249701, - 0.024309351, - 0.025077728, - 0.034659918, - 0.026362051, - 0.02448573, - 1.416744514, - 2.450618881, - 1.761972492, - 0.026288805, - 0.025001047, - 0.030125583, - 0.02488333, - 0.023717047, - 0.024042201, - 0.031057362, - 0.024267377, - 4.17186011 - ], - [ - 0.037861315, - 0.02526194, - 0.025940166, - 0.030071024, - 0.024820272, - 0.024433422, - 0.031624083, - 0.025228023, - 1.303062954, - 2.290713074, - 1.655305723, - 0.025344335, - 0.025724, - 0.02496371, - 0.02686097, - 0.032778189, - 0.023627056, - 0.024888355, - 0.029996588, - 0.024999779, - 4.441392057, - 1.663619313, - 0.023768381, - 0.026909655, - 0.028853253, - 0.025178453, - 0.023666705, - 0.026230357, - 0.032626488, - 0.024551603, - 3.868308562, - 1.569222713, - 1.666615424, - 0.024693246, - 0.023756954, - 0.025680779, - 0.02981733, - 0.024812304, - 0.023598908, - 0.024929314 - ], - [ - 0.038293636, - 0.023200632, - 0.024991227, - 0.032851745, - 0.026013211, - 0.024976407, - 0.032808954, - 0.024776518, - 0.025137443, - 2.142189244, - 5.014103322, - 0.028812147, - 0.024531851, - 0.024995596, - 0.031077829, - 0.024960899, - 0.024089807, - 0.032668975, - 0.024937861, - 0.025581829, - 1.5691347, - 2.554014967, - 0.026121495, - 0.024486979, - 0.024116193, - 0.023567849, - 0.024909399, - 0.03541515, - 0.024166147, - 0.025375051, - 0.025114686, - 2.08411544, - 2.473512449, - 0.024736377, - 0.02746773, - 0.025497245, - 0.023840137, - 0.024800958, - 0.033905253, - 0.027147702 - ], - [ - 0.042132738, - 0.026071402, - 0.027115027, - 0.031885224, - 0.024000123, - 0.024889513, - 0.031348771, - 0.025085403, - 1.281877909, - 2.231596079, - 1.689872643, - 0.02531562, - 0.026682022, - 0.023922738, - 0.024917184, - 0.033886562, - 0.024593199, - 0.024864707, - 0.029376442, - 1.804205775, - 3.84911276, - 1.703671453, - 0.023985019, - 0.027145049, - 0.028780904, - 0.023621643, - 0.024308906, - 0.025239984, - 0.032758891, - 0.025493383, - 0.024220569, - 1.530824265, - 1.657561004, - 0.024006061, - 0.02624767, - 0.02682613, - 0.032415213, - 0.024269372, - 0.024731897, - 0.025154065 - ], - [ - 0.037693408, - 0.027188227, - 0.025582912, - 0.03157872, - 0.023648565, - 0.025133045, - 0.031864789, - 0.026530352, - 0.024773714, - 2.116632792, - 4.86051907, - 0.027911705, - 0.024139274, - 0.025434202, - 0.029711926, - 0.026188593, - 0.025419472, - 0.032057549, - 0.024120565, - 0.024937626, - 1.490264903, - 2.484148172, - 1.766707327, - 0.027162333, - 0.027033083, - 0.024470158, - 0.023684642, - 0.024909488, - 0.038947022, - 0.024302864, - 0.025002225, - 1.498058832, - 2.495217078, - 0.02619442, - 0.025033964, - 0.029717561, - 0.025233283, - 0.024412055, - 0.025141582, - 0.033404209 - ] - ] - }, - "secondaryMetrics" : { - } - } -] - - diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.txt b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.txt deleted file mode 100644 index 39026135d2d4f218e985932a81e4ad92d9aa20b5..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults.txt +++ /dev/null @@ -1,33 +0,0 @@ -[info] Benchmark (collection) (size) Mode Cnt Score Error Units -[info] CollectionBenchmark.drop Vector 10000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.drop Vector 100000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.drop Vector 1000000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.drop Vector 10000000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.drop Array 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop Array 100000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop Array 1000000 ss 200 0.003 ± 0.001 s/op -[info] CollectionBenchmark.drop Array 10000000 ss 200 0.019 ± 0.002 s/op -[info] CollectionBenchmark.drop ArrayBuffer 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop ArrayBuffer 100000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop ArrayBuffer 1000000 ss 200 0.002 ± 0.001 s/op -[info] CollectionBenchmark.drop ArrayBuffer 10000000 ss 200 0.017 ± 0.007 s/op -[info] CollectionBenchmark.drop List 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop List 100000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.drop List 1000000 ss 200 0.002 ± 0.001 s/op -[info] CollectionBenchmark.drop List 10000000 ss 200 0.024 ± 0.001 s/op -[info] CollectionBenchmark.take Vector 10000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.take Vector 100000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.take Vector 1000000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.take Vector 10000000 ss 200 ≈ 10⁻⁵ s/op -[info] CollectionBenchmark.take Array 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.take Array 100000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.take Array 1000000 ss 200 0.003 ± 0.001 s/op -[info] CollectionBenchmark.take Array 10000000 ss 200 0.018 ± 0.002 s/op -[info] CollectionBenchmark.take ArrayBuffer 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.take ArrayBuffer 100000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.take ArrayBuffer 1000000 ss 200 0.003 ± 0.001 s/op -[info] CollectionBenchmark.take ArrayBuffer 10000000 ss 200 0.019 ± 0.007 s/op -[info] CollectionBenchmark.take List 10000 ss 200 ≈ 10⁻⁴ s/op -[info] CollectionBenchmark.take List 100000 ss 200 0.001 ± 0.001 s/op -[info] CollectionBenchmark.take List 1000000 ss 200 0.004 ± 0.003 s/op -[info] CollectionBenchmark.take List 10000000 ss 200 0.460 ± 0.237 s/op diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.json b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.json deleted file mode 100644 index 92c013f9bf9332ac24618b3b15947caa44259ea4..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.json +++ /dev/null @@ -1,4132 +0,0 @@ -[ - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 9.52124E-6, - "scoreError" : 4.75693155604712E-7, - "scoreConfidence" : [ - 9.04554684439529E-6, - 9.996933155604712E-6 - ], - "scorePercentiles" : { - "0.0" : 6.392E-6, - "50.0" : 9.1705E-6, - "90.0" : 1.15963E-5, - "95.0" : 1.2772349999999998E-5, - "99.0" : 1.570258E-5, - "99.9" : 2.3767E-5, - "99.99" : 2.3767E-5, - "99.999" : 2.3767E-5, - "99.9999" : 2.3767E-5, - "100.0" : 2.3767E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.3054E-5, - 1.1318E-5, - 1.1598E-5, - 1.0372E-5, - 1.4158E-5, - 1.239E-5, - 1.1564E-5, - 1.1317E-5, - 1.1174E-5, - 1.0574E-5, - 1.1772E-5, - 1.1135E-5, - 1.1614E-5, - 1.2782E-5, - 1.1541E-5, - 1.0783E-5, - 1.0465E-5, - 1.5661E-5, - 1.1037E-5, - 1.0981E-5, - 1.2782E-5, - 1.0636E-5, - 1.2589E-5, - 1.017E-5, - 9.445E-6, - 9.215E-6, - 9.908E-6, - 8.713E-6, - 8.059E-6, - 8.073E-6, - 7.85E-6, - 7.778E-6, - 8.741E-6, - 1.0966E-5, - 8.766E-6, - 7.809E-6, - 8.891E-6, - 1.1935E-5, - 8.945E-6, - 8.239E-6 - ], - [ - 1.2019E-5, - 1.0365E-5, - 1.0897E-5, - 1.0394E-5, - 1.0088E-5, - 1.0766E-5, - 1.0752E-5, - 1.0332E-5, - 1.1344E-5, - 1.0225E-5, - 1.0969E-5, - 1.1254E-5, - 1.0684E-5, - 1.0766E-5, - 1.291E-5, - 9.842E-6, - 1.0311E-5, - 1.5703E-5, - 1.0058E-5, - 9.582E-6, - 1.1525E-5, - 9.052E-6, - 8.89E-6, - 1.081E-5, - 8.859E-6, - 1.05E-5, - 9.651E-6, - 7.777E-6, - 7.331E-6, - 8.23E-6, - 7.908E-6, - 8.341E-6, - 8.63E-6, - 8.275E-6, - 9.55E-6, - 8.395E-6, - 8.499E-6, - 1.2254E-5, - 7.798E-6, - 8.514E-6 - ], - [ - 9.93E-6, - 1.0113E-5, - 9.133E-6, - 9.49E-6, - 8.946E-6, - 1.1474E-5, - 9.196E-6, - 9.428E-6, - 8.952E-6, - 8.389E-6, - 9.304E-6, - 9.877E-6, - 9.181E-6, - 8.739E-6, - 1.113E-5, - 8.816E-6, - 8.981E-6, - 1.3894E-5, - 8.781E-6, - 8.725E-6, - 1.0912E-5, - 7.88E-6, - 9.389E-6, - 9.939E-6, - 8.142E-6, - 8.113E-6, - 8.033E-6, - 7.261E-6, - 6.484E-6, - 6.646E-6, - 6.392E-6, - 6.556E-6, - 6.396E-6, - 7.767E-6, - 9.403E-6, - 7.771E-6, - 7.841E-6, - 1.1258E-5, - 7.149E-6, - 7.789E-6 - ], - [ - 1.1581E-5, - 1.0122E-5, - 9.561E-6, - 9.67E-6, - 1.124E-5, - 9.248E-6, - 9.496E-6, - 9.191E-6, - 8.541E-6, - 8.252E-6, - 8.918E-6, - 9.422E-6, - 9.919E-6, - 1.1713E-5, - 9.335E-6, - 8.968E-6, - 9.754E-6, - 1.298E-5, - 1.0346E-5, - 9.16E-6, - 1.2202E-5, - 8.557E-6, - 1.1102E-5, - 9.505E-6, - 9.211E-6, - 8.307E-6, - 7.795E-6, - 7.46E-6, - 7.291E-6, - 7.867E-6, - 7.922E-6, - 7.444E-6, - 6.652E-6, - 9.276E-6, - 6.964E-6, - 6.895E-6, - 8.144E-6, - 1.1163E-5, - 7.135E-6, - 8.1E-6 - ], - [ - 1.1132E-5, - 9.059E-6, - 9.094E-6, - 8.96E-6, - 1.1023E-5, - 9.153E-6, - 8.813E-6, - 8.768E-6, - 9.004E-6, - 8.685E-6, - 8.638E-6, - 9.696E-6, - 9.098E-6, - 1.0794E-5, - 9.034E-6, - 9.098E-6, - 8.638E-6, - 2.3767E-5, - 8.245E-6, - 8.031E-6, - 1.131E-5, - 9.129E-6, - 9.896E-6, - 7.941E-6, - 8.402E-6, - 7.52E-6, - 7.474E-6, - 7.865E-6, - 7.048E-6, - 7.877E-6, - 6.861E-6, - 6.671E-6, - 6.64E-6, - 8.652E-6, - 6.625E-6, - 6.687E-6, - 8.011E-6, - 1.1579E-5, - 7.509E-6, - 6.962E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.0312219999999994E-5, - "scoreError" : 8.267534493701422E-7, - "scoreConfidence" : [ - 9.485466550629852E-6, - 1.1138973449370136E-5 - ], - "scorePercentiles" : { - "0.0" : 6.958E-6, - "50.0" : 9.676999999999999E-6, - "90.0" : 1.27767E-5, - "95.0" : 1.4859149999999996E-5, - "99.0" : 3.110289000000002E-5, - "99.9" : 3.6256E-5, - "99.99" : 3.6256E-5, - "99.999" : 3.6256E-5, - "99.9999" : 3.6256E-5, - "100.0" : 3.6256E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.1513E-5, - 1.158E-5, - 1.2738E-5, - 1.1324E-5, - 1.1024E-5, - 1.0314E-5, - 1.2049E-5, - 9.994E-6, - 9.77E-6, - 9.718E-6, - 1.2072E-5, - 9.869E-6, - 9.583E-6, - 1.1593E-5, - 1.0687E-5, - 8.549E-6, - 1.1297E-5, - 1.6101E-5, - 9.475E-6, - 8.494E-6, - 8.142E-6, - 8.801E-6, - 8.547E-6, - 8.249E-6, - 8.666E-6, - 8.036E-6, - 1.1453E-5, - 8.74E-6, - 8.449E-6, - 7.813E-6, - 7.979E-6, - 1.4672E-5, - 8.504E-6, - 1.3733E-5, - 8.458E-6, - 7.188E-6, - 8.136E-6, - 1.2424E-5, - 8.008E-6, - 7.866E-6 - ], - [ - 1.1663E-5, - 9.914E-6, - 1.0249E-5, - 1.0391E-5, - 1.2078E-5, - 1.074E-5, - 1.0071E-5, - 1.0131E-5, - 1.2167E-5, - 9.196E-6, - 9.637E-6, - 9.445E-6, - 9.605E-6, - 1.1862E-5, - 9.556E-6, - 9.472E-6, - 1.0887E-5, - 1.6005E-5, - 9.181E-6, - 8.589E-6, - 8.429E-6, - 9.964E-6, - 8.366E-6, - 8.465E-6, - 8.281E-6, - 8.489E-6, - 1.2274E-5, - 8.272E-6, - 8.242E-6, - 7.993E-6, - 8.726E-6, - 1.7282E-5, - 1.4266E-5, - 8.111E-6, - 8.074E-6, - 8.501E-6, - 8.327E-6, - 1.2781E-5, - 8.046E-6, - 7.205E-6 - ], - [ - 1.0594E-5, - 1.0602E-5, - 1.1151E-5, - 1.0725E-5, - 1.0226E-5, - 9.848E-6, - 1.0273E-5, - 1.0781E-5, - 1.01E-5, - 9.737E-6, - 9.896E-6, - 1.0044E-5, - 9.563E-6, - 1.271E-5, - 1.0142E-5, - 8.452E-6, - 9.93E-6, - 3.1127E-5, - 2.4219E-5, - 8.514E-6, - 8.502E-6, - 8.434E-6, - 8.297E-6, - 8.676E-6, - 7.741E-6, - 8.407E-6, - 1.2601E-5, - 8.245E-6, - 7.77E-6, - 8.205E-6, - 7.714E-6, - 3.6256E-5, - 8.23E-6, - 1.3686E-5, - 8.171E-6, - 6.958E-6, - 8.304E-6, - 1.2727E-5, - 7.706E-6, - 7.684E-6 - ], - [ - 1.187E-5, - 1.1117E-5, - 1.0839E-5, - 1.0092E-5, - 1.0298E-5, - 1.0152E-5, - 1.0277E-5, - 9.636E-6, - 9.725E-6, - 1.0413E-5, - 1.0307E-5, - 1.0587E-5, - 9.717E-6, - 1.3259E-5, - 8.652E-6, - 8.337E-6, - 1.0417E-5, - 1.4869E-5, - 1.1492E-5, - 8.532E-6, - 9.344E-6, - 8.102E-6, - 9.096E-6, - 8.569E-6, - 8.335E-6, - 8.705E-6, - 1.2063E-5, - 8.527E-6, - 8.568E-6, - 7.832E-6, - 8.408E-6, - 1.6453E-5, - 8.891E-6, - 1.3782E-5, - 8.091E-6, - 8.178E-6, - 8.611E-6, - 1.2121E-5, - 7.906E-6, - 8.007E-6 - ], - [ - 1.2209E-5, - 1.0556E-5, - 1.2835E-5, - 1.066E-5, - 1.0288E-5, - 1.0472E-5, - 1.0613E-5, - 9.825E-6, - 9.856E-6, - 1.0295E-5, - 1.0321E-5, - 1.0286E-5, - 9.548E-6, - 1.2951E-5, - 1.0239E-5, - 8.438E-6, - 1.0773E-5, - 2.8716E-5, - 1.0977E-5, - 1.0229E-5, - 8.65E-6, - 8.304E-6, - 8.027E-6, - 8.564E-6, - 8.202E-6, - 8.498E-6, - 1.2563E-5, - 8.46E-6, - 8.042E-6, - 8.353E-6, - 8.668E-6, - 1.7366E-5, - 8.231E-6, - 1.3029E-5, - 7.152E-6, - 8.245E-6, - 8.56E-6, - 1.1558E-5, - 8.062E-6, - 8.157E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 1.3031209999999994E-5, - "scoreError" : 8.839573714000302E-7, - "scoreConfidence" : [ - 1.2147252628599964E-5, - 1.3915167371400024E-5 - ], - "scorePercentiles" : { - "0.0" : 8.203E-6, - "50.0" : 1.21425E-5, - "90.0" : 1.81526E-5, - "95.0" : 2.1064299999999987E-5, - "99.0" : 2.440447E-5, - "99.9" : 2.4566E-5, - "99.99" : 2.4566E-5, - "99.999" : 2.4566E-5, - "99.9999" : 2.4566E-5, - "100.0" : 2.4566E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.7701E-5, - 1.1699E-5, - 1.2014E-5, - 1.1548E-5, - 1.4038E-5, - 1.4886E-5, - 1.5881E-5, - 1.146E-5, - 1.1463E-5, - 1.1346E-5, - 1.0746E-5, - 1.0914E-5, - 1.1587E-5, - 1.8863E-5, - 1.1978E-5, - 1.0185E-5, - 1.1309E-5, - 9.262E-6, - 9.124E-6, - 9.331E-6, - 1.2438E-5, - 1.4078E-5, - 1.3865E-5, - 1.4558E-5, - 1.3723E-5, - 1.4404E-5, - 2.3557E-5, - 1.0411E-5, - 9.361E-6, - 9.998E-6, - 9.784E-6, - 1.6717E-5, - 1.5624E-5, - 9.708E-6, - 8.536E-6, - 9.959E-6, - 8.962E-6, - 1.428E-5, - 9.007E-6, - 1.5873E-5 - ], - [ - 1.8041E-5, - 1.2819E-5, - 1.1652E-5, - 1.1744E-5, - 1.4823E-5, - 1.4952E-5, - 1.6583E-5, - 1.2186E-5, - 1.1793E-5, - 1.1364E-5, - 2.0044E-5, - 9.636E-6, - 9.083E-6, - 2.1821E-5, - 1.1991E-5, - 2.1118E-5, - 1.9486E-5, - 1.1048E-5, - 1.0744E-5, - 9.471E-6, - 1.1353E-5, - 1.4114E-5, - 1.3409E-5, - 1.4314E-5, - 1.4267E-5, - 1.4798E-5, - 2.3343E-5, - 1.0669E-5, - 9.136E-6, - 9.09E-6, - 9.017E-6, - 1.588E-5, - 1.5669E-5, - 9.315E-6, - 8.34E-6, - 8.93E-6, - 8.685E-6, - 1.3809E-5, - 8.203E-6, - 1.5728E-5 - ], - [ - 1.845E-5, - 1.2526E-5, - 1.2513E-5, - 1.2933E-5, - 1.5615E-5, - 1.5752E-5, - 1.6849E-5, - 1.2718E-5, - 1.3193E-5, - 1.2676E-5, - 1.9199E-5, - 1.1066E-5, - 8.987E-6, - 2.1134E-5, - 1.2154E-5, - 8.878E-6, - 1.2427E-5, - 9.599E-6, - 9.156E-6, - 8.953E-6, - 1.1739E-5, - 1.4886E-5, - 1.6949E-5, - 1.489E-5, - 1.4275E-5, - 1.5618E-5, - 2.4566E-5, - 1.1709E-5, - 8.981E-6, - 8.74E-6, - 1.1851E-5, - 1.9375E-5, - 1.5406E-5, - 8.727E-6, - 8.781E-6, - 8.7E-6, - 8.263E-6, - 1.4209E-5, - 8.537E-6, - 1.5678E-5 - ], - [ - 1.9232E-5, - 1.2008E-5, - 1.1993E-5, - 1.2104E-5, - 1.7975E-5, - 1.5551E-5, - 1.6566E-5, - 1.3063E-5, - 1.1643E-5, - 1.1146E-5, - 1.9735E-5, - 9.955E-6, - 9.22E-6, - 2.1364E-5, - 1.1568E-5, - 1.2322E-5, - 1.2289E-5, - 9.873E-6, - 9.347E-6, - 8.457E-6, - 9.202E-6, - 1.6277E-5, - 1.424E-5, - 1.3797E-5, - 1.3853E-5, - 1.6402E-5, - 2.4253E-5, - 1.0871E-5, - 1.034E-5, - 1.0604E-5, - 9.664E-6, - 1.7323E-5, - 1.588E-5, - 9.792E-6, - 9.43E-6, - 1.1936E-5, - 1.0693E-5, - 1.616E-5, - 9.555E-6, - 1.688E-5 - ], - [ - 1.7725E-5, - 1.2499E-5, - 1.2218E-5, - 1.2131E-5, - 1.54E-5, - 1.6504E-5, - 1.6562E-5, - 1.3237E-5, - 1.232E-5, - 1.2309E-5, - 1.9721E-5, - 1.102E-5, - 9.1E-6, - 2.2408E-5, - 1.0961E-5, - 9.623E-6, - 1.2E-5, - 9.676E-6, - 9.806E-6, - 9.293E-6, - 9.387E-6, - 1.5296E-5, - 1.4621E-5, - 1.5034E-5, - 1.4067E-5, - 1.3953E-5, - 2.4406E-5, - 1.0681E-5, - 1.0082E-5, - 9.953E-6, - 9.756E-6, - 1.8165E-5, - 1.5343E-5, - 8.411E-6, - 8.748E-6, - 8.788E-6, - 8.804E-6, - 1.3542E-5, - 8.441E-6, - 1.6384E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 1.7532130000000003E-5, - "scoreError" : 1.1958193186467489E-6, - "scoreConfidence" : [ - 1.6336310681353254E-5, - 1.8727949318646752E-5 - ], - "scorePercentiles" : { - "0.0" : 1.0746E-5, - "50.0" : 1.77505E-5, - "90.0" : 2.24916E-5, - "95.0" : 2.72908E-5, - "99.0" : 3.354428E-5, - "99.9" : 4.8553E-5, - "99.99" : 4.8553E-5, - "99.999" : 4.8553E-5, - "99.9999" : 4.8553E-5, - "100.0" : 4.8553E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.0305E-5, - 1.9105E-5, - 1.9004E-5, - 1.5399E-5, - 1.9714E-5, - 1.7885E-5, - 1.9478E-5, - 1.4212E-5, - 1.7924E-5, - 1.5369E-5, - 2.4777E-5, - 1.7033E-5, - 1.7798E-5, - 1.2474E-5, - 1.9047E-5, - 1.2282E-5, - 1.7743E-5, - 1.8719E-5, - 1.5024E-5, - 1.7678E-5, - 1.6763E-5, - 1.7473E-5, - 1.1969E-5, - 2.9778E-5, - 1.996E-5, - 1.1451E-5, - 4.8553E-5, - 1.1291E-5, - 1.6628E-5, - 1.2264E-5, - 1.7898E-5, - 1.1253E-5, - 1.0746E-5, - 1.855E-5, - 1.3291E-5, - 1.6626E-5, - 1.2992E-5, - 1.6369E-5, - 1.2328E-5, - 1.2569E-5 - ], - [ - 2.1961E-5, - 2.0498E-5, - 1.4835E-5, - 1.9224E-5, - 3.3551E-5, - 1.4979E-5, - 1.9223E-5, - 1.7718E-5, - 1.2044E-5, - 2.3624E-5, - 1.4161E-5, - 1.8739E-5, - 1.3821E-5, - 1.8868E-5, - 1.1367E-5, - 1.9402E-5, - 1.4091E-5, - 1.2833E-5, - 1.8522E-5, - 1.2709E-5, - 2.704E-5, - 3.2312E-5, - 1.9812E-5, - 2.0853E-5, - 1.8535E-5, - 1.9354E-5, - 1.8393E-5, - 1.8784E-5, - 1.3046E-5, - 1.8715E-5, - 1.2055E-5, - 1.1652E-5, - 1.7463E-5, - 1.2338E-5, - 1.7967E-5, - 1.1218E-5, - 1.8738E-5, - 1.258E-5, - 1.2703E-5, - 1.755E-5 - ], - [ - 2.0854E-5, - 2.0375E-5, - 1.8077E-5, - 2.0268E-5, - 2.0678E-5, - 1.6746E-5, - 2.1464E-5, - 1.6583E-5, - 1.7724E-5, - 1.6638E-5, - 2.5192E-5, - 1.3111E-5, - 1.42E-5, - 1.8642E-5, - 1.9203E-5, - 1.8283E-5, - 1.5303E-5, - 1.8525E-5, - 1.3203E-5, - 1.9368E-5, - 1.8474E-5, - 1.3311E-5, - 1.8885E-5, - 1.8896E-5, - 3.1831E-5, - 1.2299E-5, - 3.2879E-5, - 1.168E-5, - 1.0983E-5, - 1.7881E-5, - 1.6021E-5, - 1.7758E-5, - 1.2961E-5, - 1.849E-5, - 1.2843E-5, - 1.3996E-5, - 1.7565E-5, - 1.3715E-5, - 1.7292E-5, - 1.2063E-5 - ], - [ - 2.2105E-5, - 1.9375E-5, - 1.4141E-5, - 2.208E-5, - 1.8335E-5, - 1.518E-5, - 2.0287E-5, - 1.7282E-5, - 1.9898E-5, - 1.7155E-5, - 1.4924E-5, - 1.9789E-5, - 1.2374E-5, - 1.9818E-5, - 1.459E-5, - 1.9022E-5, - 1.3612E-5, - 1.2619E-5, - 1.8861E-5, - 1.6878E-5, - 2.7304E-5, - 1.3258E-5, - 1.8716E-5, - 2.4441E-5, - 2.2849E-5, - 1.8338E-5, - 2.6444E-5, - 1.7943E-5, - 1.1324E-5, - 1.8109E-5, - 1.1837E-5, - 1.217E-5, - 1.6849E-5, - 1.2167E-5, - 1.7939E-5, - 1.1703E-5, - 1.8008E-5, - 2.7648E-5, - 1.7262E-5, - 1.1975E-5 - ], - [ - 2.2516E-5, - 2.2272E-5, - 2.2534E-5, - 1.8038E-5, - 2.0077E-5, - 2.1546E-5, - 1.5422E-5, - 2.1843E-5, - 1.2691E-5, - 2.6435E-5, - 1.5268E-5, - 1.9946E-5, - 1.2724E-5, - 1.8577E-5, - 1.4354E-5, - 1.2928E-5, - 1.9172E-5, - 1.2862E-5, - 1.896E-5, - 1.2351E-5, - 2.7411E-5, - 1.2093E-5, - 1.1757E-5, - 3.2641E-5, - 1.8696E-5, - 1.9098E-5, - 1.968E-5, - 1.8298E-5, - 1.3455E-5, - 1.1636E-5, - 1.866E-5, - 1.2936E-5, - 1.7517E-5, - 1.2136E-5, - 1.911E-5, - 1.4028E-5, - 1.2447E-5, - 1.8216E-5, - 1.5333E-5, - 1.8893E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1144723499999989E-4, - "scoreError" : 1.1058793358501485E-5, - "scoreConfidence" : [ - 1.0038844164149841E-4, - 1.2250602835850137E-4 - ], - "scorePercentiles" : { - "0.0" : 5.7016E-5, - "50.0" : 1.45703E-4, - "90.0" : 1.597454E-4, - "95.0" : 1.6436925E-4, - "99.0" : 1.7420876000000002E-4, - "99.9" : 2.07914E-4, - "99.99" : 2.07914E-4, - "99.999" : 2.07914E-4, - "99.9999" : 2.07914E-4, - "100.0" : 2.07914E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.72304E-4, - 1.67911E-4, - 1.55196E-4, - 1.53195E-4, - 1.60621E-4, - 1.55215E-4, - 1.55227E-4, - 1.56133E-4, - 1.5369E-4, - 1.59786E-4, - 1.55942E-4, - 1.56158E-4, - 1.56785E-4, - 1.56749E-4, - 1.6172E-4, - 1.55615E-4, - 1.55021E-4, - 1.55684E-4, - 1.60043E-4, - 1.61992E-4, - 7.0253E-5, - 6.3163E-5, - 5.9484E-5, - 5.9629E-5, - 6.3695E-5, - 6.1474E-5, - 5.9301E-5, - 5.992E-5, - 6.3813E-5, - 6.4601E-5, - 6.1235E-5, - 5.7016E-5, - 6.0039E-5, - 6.0477E-5, - 5.9862E-5, - 6.5156E-5, - 6.2693E-5, - 6.7376E-5, - 6.1506E-5, - 6.4506E-5 - ], - [ - 1.74228E-4, - 1.64414E-4, - 1.56095E-4, - 1.51202E-4, - 1.5938E-4, - 1.50959E-4, - 1.51477E-4, - 1.5426E-4, - 1.5339E-4, - 1.54813E-4, - 1.54039E-4, - 1.55465E-4, - 1.56357E-4, - 1.51921E-4, - 1.56928E-4, - 1.54485E-4, - 1.58881E-4, - 1.52511E-4, - 1.55134E-4, - 1.57349E-4, - 1.40447E-4, - 6.411E-5, - 5.9396E-5, - 6.2892E-5, - 6.5923E-5, - 6.3789E-5, - 6.2649E-5, - 6.1297E-5, - 6.338E-5, - 6.4422E-5, - 6.9216E-5, - 7.026E-5, - 6.8288E-5, - 7.6116E-5, - 6.1955E-5, - 6.5637E-5, - 6.1686E-5, - 6.8285E-5, - 7.2524E-5, - 6.4846E-5 - ], - [ - 1.7067E-4, - 1.65651E-4, - 1.52661E-4, - 1.50977E-4, - 1.53092E-4, - 1.53146E-4, - 1.51284E-4, - 1.55318E-4, - 1.53782E-4, - 1.51287E-4, - 1.61462E-4, - 1.53462E-4, - 1.5406E-4, - 1.55853E-4, - 1.54704E-4, - 1.53947E-4, - 1.52416E-4, - 1.51976E-4, - 1.55539E-4, - 1.58258E-4, - 1.10125E-4, - 6.5484E-5, - 5.9492E-5, - 5.8506E-5, - 6.1445E-5, - 6.0726E-5, - 6.0171E-5, - 5.8945E-5, - 6.5792E-5, - 5.9667E-5, - 6.6712E-5, - 5.818E-5, - 6.6583E-5, - 5.9511E-5, - 5.9473E-5, - 6.32E-5, - 5.9153E-5, - 6.4371E-5, - 5.9452E-5, - 6.1028E-5 - ], - [ - 1.68734E-4, - 1.71234E-4, - 1.53154E-4, - 1.54617E-4, - 1.54028E-4, - 1.57453E-4, - 1.53551E-4, - 1.55169E-4, - 1.54088E-4, - 1.53981E-4, - 1.53111E-4, - 1.59078E-4, - 1.60794E-4, - 1.55266E-4, - 1.52786E-4, - 1.55195E-4, - 1.5476E-4, - 1.59012E-4, - 1.52918E-4, - 1.54E-4, - 1.13562E-4, - 6.7098E-5, - 6.1534E-5, - 5.8947E-5, - 5.9787E-5, - 6.5946E-5, - 6.677E-5, - 5.9298E-5, - 5.9656E-5, - 5.9555E-5, - 6.5343E-5, - 5.8898E-5, - 6.3709E-5, - 5.9689E-5, - 5.9902E-5, - 6.2573E-5, - 6.3671E-5, - 6.5813E-5, - 6.1154E-5, - 6.2908E-5 - ], - [ - 1.67636E-4, - 1.63519E-4, - 1.56595E-4, - 1.62045E-4, - 1.5114E-4, - 1.52722E-4, - 1.52159E-4, - 1.53283E-4, - 1.5202E-4, - 1.50965E-4, - 1.52861E-4, - 1.51466E-4, - 1.535E-4, - 1.52793E-4, - 1.58481E-4, - 1.51922E-4, - 1.51959E-4, - 2.07914E-4, - 1.53874E-4, - 1.62573E-4, - 1.06989E-4, - 1.20139E-4, - 5.8099E-5, - 6.3582E-5, - 5.7902E-5, - 9.0699E-5, - 6.5559E-5, - 6.0289E-5, - 6.7203E-5, - 5.9788E-5, - 6.1242E-5, - 6.2963E-5, - 5.8111E-5, - 6.011E-5, - 6.3339E-5, - 6.539E-5, - 5.7328E-5, - 9.2792E-5, - 5.943E-5, - 6.2171E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 2.55179115E-4, - "scoreError" : 3.1801450215650774E-5, - "scoreConfidence" : [ - 2.2337766478434923E-4, - 2.8698056521565075E-4 - ], - "scorePercentiles" : { - "0.0" : 1.63584E-4, - "50.0" : 1.73804E-4, - "90.0" : 4.875742E-4, - "95.0" : 4.9233455E-4, - "99.0" : 5.054576800000001E-4, - "99.9" : 5.18162E-4, - "99.99" : 5.18162E-4, - "99.999" : 5.18162E-4, - "99.9999" : 5.18162E-4, - "100.0" : 5.18162E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.69814E-4, - 4.66001E-4, - 4.90263E-4, - 4.83266E-4, - 4.77248E-4, - 4.75294E-4, - 5.18162E-4, - 4.82859E-4, - 4.82676E-4, - 4.94289E-4, - 3.38816E-4, - 2.9707E-4, - 1.89404E-4, - 1.7874E-4, - 1.74514E-4, - 1.73767E-4, - 1.76197E-4, - 1.79912E-4, - 1.85214E-4, - 2.01282E-4, - 1.9707E-4, - 1.96374E-4, - 2.01486E-4, - 2.00322E-4, - 2.05622E-4, - 2.04221E-4, - 2.10117E-4, - 1.94349E-4, - 1.92845E-4, - 1.91404E-4, - 1.98886E-4, - 1.92362E-4, - 2.35001E-4, - 1.83801E-4, - 1.63637E-4, - 1.64196E-4, - 1.64627E-4, - 1.68615E-4, - 1.64896E-4, - 1.63584E-4 - ], - [ - 4.70961E-4, - 4.73608E-4, - 4.89021E-4, - 4.92405E-4, - 4.81514E-4, - 4.81305E-4, - 4.79127E-4, - 4.90761E-4, - 4.80958E-4, - 4.82943E-4, - 1.83919E-4, - 1.72683E-4, - 1.70773E-4, - 1.70708E-4, - 2.07872E-4, - 1.67075E-4, - 1.68207E-4, - 1.69573E-4, - 1.67872E-4, - 1.67649E-4, - 1.73841E-4, - 1.68009E-4, - 1.66324E-4, - 1.69324E-4, - 1.72411E-4, - 1.69353E-4, - 1.67896E-4, - 1.67347E-4, - 1.79782E-4, - 1.68463E-4, - 1.68493E-4, - 1.67867E-4, - 1.82353E-4, - 1.68972E-4, - 1.6794E-4, - 1.68081E-4, - 1.65634E-4, - 1.73629E-4, - 1.67111E-4, - 1.66074E-4 - ], - [ - 4.79347E-4, - 4.81852E-4, - 4.86665E-4, - 4.90996E-4, - 4.82579E-4, - 4.77953E-4, - 4.79949E-4, - 4.82669E-4, - 4.92498E-4, - 4.7828E-4, - 2.4163E-4, - 1.71169E-4, - 1.68482E-4, - 1.9724E-4, - 1.67666E-4, - 1.66023E-4, - 1.69169E-4, - 1.67253E-4, - 1.66721E-4, - 1.69939E-4, - 1.725E-4, - 1.66913E-4, - 1.6588E-4, - 1.6566E-4, - 1.68495E-4, - 1.67994E-4, - 1.68789E-4, - 1.67576E-4, - 1.68139E-4, - 1.72393E-4, - 1.69919E-4, - 1.68377E-4, - 1.84671E-4, - 1.67739E-4, - 1.66777E-4, - 1.67156E-4, - 1.67266E-4, - 1.76223E-4, - 1.67388E-4, - 1.67255E-4 - ], - [ - 4.78435E-4, - 4.74247E-4, - 4.78663E-4, - 4.89756E-4, - 4.86712E-4, - 4.90375E-4, - 4.81261E-4, - 4.88117E-4, - 4.8767E-4, - 4.82233E-4, - 2.22277E-4, - 1.71539E-4, - 1.69622E-4, - 1.70652E-4, - 1.70406E-4, - 1.67369E-4, - 1.68473E-4, - 1.68708E-4, - 1.69104E-4, - 1.68687E-4, - 1.71794E-4, - 1.66954E-4, - 1.69363E-4, - 1.67856E-4, - 1.80825E-4, - 1.69824E-4, - 1.69472E-4, - 1.67282E-4, - 1.6959E-4, - 1.67191E-4, - 1.66411E-4, - 1.8128E-4, - 1.81413E-4, - 1.69638E-4, - 1.71267E-4, - 1.68301E-4, - 1.66623E-4, - 1.73987E-4, - 1.68168E-4, - 1.6645E-4 - ], - [ - 4.77783E-4, - 4.89708E-4, - 4.98561E-4, - 4.89785E-4, - 4.99858E-4, - 5.0551E-4, - 4.81543E-4, - 4.94473E-4, - 5.00278E-4, - 4.94226E-4, - 2.31001E-4, - 1.75226E-4, - 1.70128E-4, - 2.11101E-4, - 1.69455E-4, - 1.69622E-4, - 1.69364E-4, - 1.69646E-4, - 1.69039E-4, - 1.7109E-4, - 2.17562E-4, - 1.6694E-4, - 1.69472E-4, - 1.68692E-4, - 1.69388E-4, - 1.72158E-4, - 1.67787E-4, - 1.70844E-4, - 1.67531E-4, - 1.696E-4, - 1.81916E-4, - 1.70215E-4, - 1.95457E-4, - 1.81038E-4, - 1.76022E-4, - 1.74252E-4, - 1.94783E-4, - 2.06366E-4, - 1.90443E-4, - 1.88734E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0025111448600000008, - "scoreError" : 3.413240734944437E-4, - "scoreConfidence" : [ - 0.002169820786505557, - 0.0028524689334944444 - ], - "scorePercentiles" : { - "0.0" : 0.001533834, - "50.0" : 0.0015960599999999998, - "90.0" : 0.004735151, - "95.0" : 0.0047711137, - "99.0" : 0.005409003780000005, - "99.9" : 0.007415289, - "99.99" : 0.007415289, - "99.999" : 0.007415289, - "99.9999" : 0.007415289, - "100.0" : 0.007415289 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001606733, - 0.004668471, - 0.004689762, - 0.001578157, - 0.001578219, - 0.001572034, - 0.001605855, - 0.001614956, - 0.001586255, - 0.001582068, - 0.001573246, - 0.001595203, - 0.004719663, - 0.004745299, - 0.004619791, - 0.004568319, - 0.001583052, - 0.00154875, - 0.001543738, - 0.001711218, - 0.001588839, - 0.001534018, - 0.001533834, - 0.001539024, - 0.001540677, - 0.001568416, - 0.001546305, - 0.001571916, - 0.001587221, - 0.001575262, - 0.0015771, - 0.001582438, - 0.001599251, - 0.001600072, - 0.002736418, - 0.00472825, - 0.004720962, - 0.00477169, - 0.004743895, - 0.004761516 - ], - [ - 0.001601144, - 0.004705643, - 0.004720799, - 0.001582594, - 0.001579686, - 0.00157747, - 0.001574876, - 0.001615191, - 0.001599481, - 0.001581197, - 0.001611557, - 0.001595867, - 0.004721589, - 0.0047705, - 0.00472395, - 0.004735522, - 0.001611829, - 0.001581148, - 0.001599294, - 0.001600055, - 0.00160255, - 0.001578724, - 0.001570322, - 0.001557443, - 0.0015404, - 0.001580706, - 0.001549512, - 0.00154161, - 0.001545848, - 0.001543452, - 0.001543932, - 0.001544103, - 0.001541606, - 0.001541332, - 0.002699202, - 0.004634181, - 0.004603522, - 0.004643915, - 0.00467205, - 0.004754974 - ], - [ - 0.001568945, - 0.004624836, - 0.004687159, - 0.001554116, - 0.001601489, - 0.001550261, - 0.001603436, - 0.00161326, - 0.001586279, - 0.001579238, - 0.001583683, - 0.001613788, - 0.004771146, - 0.004822154, - 0.004694494, - 0.00469159, - 0.001610654, - 0.001578352, - 0.001536564, - 0.001554347, - 0.001591453, - 0.001541334, - 0.001559631, - 0.001542248, - 0.001539038, - 0.001580713, - 0.00153994, - 0.002033616, - 0.00154284, - 0.001828756, - 0.00154439, - 0.001555188, - 0.001540213, - 0.001537399, - 0.002636448, - 0.004672907, - 0.004743641, - 0.004737168, - 0.004796059, - 0.00491616 - ], - [ - 0.001601446, - 0.004759075, - 0.007415289, - 0.002134026, - 0.001589728, - 0.001578225, - 0.001584776, - 0.001616313, - 0.001585174, - 0.001603429, - 0.001563601, - 0.001601965, - 0.004713263, - 0.004727506, - 0.004731812, - 0.004687223, - 0.001620178, - 0.001594548, - 0.001573887, - 0.001587389, - 0.001572911, - 0.001571173, - 0.001571445, - 0.00158127, - 0.001574942, - 0.001624171, - 0.001606328, - 0.001597723, - 0.001582975, - 0.001571619, - 0.001573502, - 0.001578201, - 0.001576189, - 0.001591389, - 0.003353914, - 0.004677412, - 0.00471393, - 0.004808844, - 0.00487805, - 0.005413982 - ], - [ - 0.001621912, - 0.004652049, - 0.004705901, - 0.001590531, - 0.001589109, - 0.00157325, - 0.00159001, - 0.001616484, - 0.001621392, - 0.001607012, - 0.001574148, - 0.001596767, - 0.004717198, - 0.004687621, - 0.004711427, - 0.004697882, - 0.00160378, - 0.001583252, - 0.001588393, - 0.001588235, - 0.001581598, - 0.001568512, - 0.001590737, - 0.001596253, - 0.001580081, - 0.001617834, - 0.001584403, - 0.001584483, - 0.001595291, - 0.001578295, - 0.001590058, - 0.00161959, - 0.001582825, - 0.002177614, - 0.004718055, - 0.004722744, - 0.004767414, - 0.00471165, - 0.004804816, - 0.004669941 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.01842779793499999, - "scoreError" : 0.001762047444700974, - "scoreConfidence" : [ - 0.016665750490299017, - 0.020189845379700963 - ], - "scorePercentiles" : { - "0.0" : 0.014879851, - "50.0" : 0.015533652, - "90.0" : 0.0216740172, - "95.0" : 0.04443578139999993, - "99.0" : 0.04697062417, - "99.9" : 0.047708844, - "99.99" : 0.047708844, - "99.999" : 0.047708844, - "99.9999" : 0.047708844, - "100.0" : 0.047708844 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.019715242, - 0.016262469, - 0.015898438, - 0.044736588, - 0.021109665, - 0.015231639, - 0.016199602, - 0.038591326, - 0.015544384, - 0.015249318, - 0.015430339, - 0.046972515, - 0.020255935, - 0.015457, - 0.015290209, - 0.016832884, - 0.022143258, - 0.015182579, - 0.015158036, - 0.015150406, - 0.015393553, - 0.02127114, - 0.015441777, - 0.015030968, - 0.015980989, - 0.015309038, - 0.015164094, - 0.01549493, - 0.015638461, - 0.015387764, - 0.022582533, - 0.015982421, - 0.015397968, - 0.015242642, - 0.015082663, - 0.038720456, - 0.015176836, - 0.015541561, - 0.015806165, - 0.015391163 - ], - [ - 0.019213233, - 0.015195522, - 0.015177655, - 0.046783432, - 0.021161785, - 0.015463449, - 0.017045831, - 0.034617162, - 0.015594621, - 0.015312445, - 0.017553194, - 0.04632445, - 0.0196296, - 0.015081282, - 0.015313376, - 0.016447151, - 0.021678178, - 0.015341918, - 0.015255193, - 0.015968863, - 0.015660955, - 0.021258483, - 0.015577509, - 0.01526688, - 0.015495193, - 0.01545285, - 0.015125996, - 0.015279208, - 0.015314566, - 0.01522762, - 0.02037686, - 0.015775232, - 0.015488139, - 0.015354816, - 0.015156306, - 0.021076139, - 0.015395694, - 0.01555339, - 0.01529134, - 0.015296001 - ], - [ - 0.019592638, - 0.015238246, - 0.015329181, - 0.045512597, - 0.02140102, - 0.015219329, - 0.016337343, - 0.036605119, - 0.015391838, - 0.015248626, - 0.015542861, - 0.045028004, - 0.020059904, - 0.016019962, - 0.015427614, - 0.017071832, - 0.020319731, - 0.015232384, - 0.015259331, - 0.015942386, - 0.015525743, - 0.015913033, - 0.015420185, - 0.015106084, - 0.015115159, - 0.015690638, - 0.016046806, - 0.015863496, - 0.01577689, - 0.01536436, - 0.02163657, - 0.015382715, - 0.015585163, - 0.014966764, - 0.014999291, - 0.014923374, - 0.0154487, - 0.015640759, - 0.015409534, - 0.015542755 - ], - [ - 0.019310537, - 0.015430374, - 0.015640914, - 0.045640089, - 0.021222739, - 0.015141192, - 0.016010943, - 0.033801735, - 0.015423721, - 0.015090101, - 0.015581642, - 0.046159284, - 0.020032631, - 0.01547753, - 0.015045585, - 0.016564397, - 0.020553577, - 0.015341819, - 0.015926177, - 0.015221855, - 0.015316898, - 0.015490555, - 0.015283564, - 0.015182818, - 0.015210287, - 0.015729992, - 0.016114304, - 0.015927454, - 0.015702963, - 0.015208285, - 0.021909728, - 0.015386038, - 0.019458675, - 0.016814371, - 0.015616497, - 0.014879851, - 0.015287016, - 0.016456219, - 0.01529192, - 0.015315094 - ], - [ - 0.019155198, - 0.015568396, - 0.016132828, - 0.047708844, - 0.021210017, - 0.015267597, - 0.016349676, - 0.036018824, - 0.01512888, - 0.01535029, - 0.015919348, - 0.045472057, - 0.019420036, - 0.015308105, - 0.015291027, - 0.017118402, - 0.020772175, - 0.015617184, - 0.015412754, - 0.015359281, - 0.015200059, - 0.015470744, - 0.015502219, - 0.015305056, - 0.015132738, - 0.016374836, - 0.016368097, - 0.015396714, - 0.015515947, - 0.015394844, - 0.020679651, - 0.015144463, - 0.01545266, - 0.015388377, - 0.015675925, - 0.014981293, - 0.015200143, - 0.015560107, - 0.015546011, - 0.015320977 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1945109499999994E-4, - "scoreError" : 4.248637046125932E-6, - "scoreConfidence" : [ - 1.15202457953874E-4, - 1.2369973204612588E-4 - ], - "scorePercentiles" : { - "0.0" : 1.11062E-4, - "50.0" : 1.15004E-4, - "90.0" : 1.28183E-4, - "95.0" : 1.4650589999999988E-4, - "99.0" : 2.4359480000000024E-4, - "99.9" : 2.4919E-4, - "99.99" : 2.4919E-4, - "99.999" : 2.4919E-4, - "99.9999" : 2.4919E-4, - "100.0" : 2.4919E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.28441E-4, - 1.25861E-4, - 1.14082E-4, - 1.14078E-4, - 1.11775E-4, - 1.20328E-4, - 1.1627E-4, - 1.13987E-4, - 1.11973E-4, - 1.16889E-4, - 1.14472E-4, - 1.13196E-4, - 1.18362E-4, - 1.20518E-4, - 1.14462E-4, - 1.12581E-4, - 1.132E-4, - 1.12517E-4, - 1.19686E-4, - 1.15904E-4, - 1.12651E-4, - 1.15083E-4, - 1.12763E-4, - 1.13846E-4, - 1.14166E-4, - 1.12258E-4, - 2.4919E-4, - 1.12338E-4, - 1.49785E-4, - 1.1266E-4, - 1.36282E-4, - 1.49348E-4, - 1.13312E-4, - 1.11842E-4, - 1.13452E-4, - 1.1202E-4, - 1.22234E-4, - 1.1666E-4, - 1.16645E-4, - 1.16424E-4 - ], - [ - 1.31012E-4, - 1.22621E-4, - 1.12085E-4, - 1.13548E-4, - 1.12025E-4, - 1.18983E-4, - 1.14035E-4, - 1.13266E-4, - 1.14386E-4, - 1.14522E-4, - 1.13665E-4, - 1.11838E-4, - 1.14663E-4, - 1.12898E-4, - 1.11989E-4, - 1.16904E-4, - 1.11896E-4, - 1.12955E-4, - 1.12901E-4, - 1.12588E-4, - 1.11927E-4, - 1.16011E-4, - 1.15946E-4, - 1.12593E-4, - 1.1466E-4, - 1.16718E-4, - 1.17772E-4, - 1.12702E-4, - 1.15023E-4, - 1.14194E-4, - 1.19849E-4, - 1.20717E-4, - 1.12553E-4, - 1.12553E-4, - 1.1303E-4, - 1.16869E-4, - 1.17187E-4, - 1.14603E-4, - 1.15199E-4, - 1.17736E-4 - ], - [ - 1.33692E-4, - 1.22601E-4, - 1.14912E-4, - 1.13942E-4, - 1.13615E-4, - 1.15213E-4, - 1.15624E-4, - 1.15942E-4, - 1.12152E-4, - 1.14096E-4, - 1.11908E-4, - 1.12333E-4, - 1.16662E-4, - 1.1346E-4, - 1.12671E-4, - 1.13163E-4, - 1.18387E-4, - 1.18417E-4, - 1.12483E-4, - 1.14786E-4, - 1.12839E-4, - 1.13588E-4, - 1.11707E-4, - 1.12395E-4, - 1.13599E-4, - 1.15276E-4, - 2.15954E-4, - 1.14606E-4, - 1.31619E-4, - 1.1462E-4, - 1.18439E-4, - 2.05213E-4, - 1.17625E-4, - 1.14597E-4, - 1.14075E-4, - 1.12E-4, - 1.16725E-4, - 1.16922E-4, - 1.13214E-4, - 1.47044E-4 - ], - [ - 1.3184E-4, - 1.30622E-4, - 1.14128E-4, - 1.19215E-4, - 1.16979E-4, - 1.15385E-4, - 1.18962E-4, - 1.16605E-4, - 1.17861E-4, - 1.15574E-4, - 1.11883E-4, - 1.15425E-4, - 1.2091E-4, - 1.14322E-4, - 1.17386E-4, - 1.1508E-4, - 1.16107E-4, - 1.14068E-4, - 1.18263E-4, - 1.13638E-4, - 1.11924E-4, - 1.16643E-4, - 1.16718E-4, - 1.16807E-4, - 1.1349E-4, - 1.16919E-4, - 2.43874E-4, - 1.14857E-4, - 1.565E-4, - 1.19295E-4, - 1.13557E-4, - 1.85017E-4, - 1.14294E-4, - 1.15751E-4, - 1.12195E-4, - 1.12189E-4, - 1.16329E-4, - 1.2325E-4, - 1.16011E-4, - 1.15357E-4 - ], - [ - 1.28458E-4, - 1.34164E-4, - 1.12749E-4, - 1.14419E-4, - 1.11668E-4, - 1.13399E-4, - 1.17476E-4, - 1.15368E-4, - 1.15843E-4, - 1.14757E-4, - 1.11062E-4, - 1.15072E-4, - 1.14985E-4, - 1.16623E-4, - 1.14082E-4, - 1.12051E-4, - 1.18155E-4, - 1.16196E-4, - 1.11781E-4, - 1.16917E-4, - 1.16234E-4, - 1.18527E-4, - 1.13071E-4, - 1.31499E-4, - 1.17175E-4, - 1.14046E-4, - 1.16308E-4, - 1.14324E-4, - 1.18464E-4, - 1.12672E-4, - 1.13939E-4, - 1.50435E-4, - 1.15078E-4, - 1.16755E-4, - 1.18728E-4, - 1.13627E-4, - 1.17352E-4, - 1.12587E-4, - 1.14673E-4, - 1.17991E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.924638649999999E-4, - "scoreError" : 1.5392262632764065E-5, - "scoreConfidence" : [ - 1.7707160236723584E-4, - 2.0785612763276397E-4 - ], - "scorePercentiles" : { - "0.0" : 1.4645E-4, - "50.0" : 1.529845E-4, - "90.0" : 2.246841E-4, - "95.0" : 4.1552684999999904E-4, - "99.0" : 4.3108221E-4, - "99.9" : 4.33634E-4, - "99.99" : 4.33634E-4, - "99.999" : 4.33634E-4, - "99.9999" : 4.33634E-4, - "100.0" : 4.33634E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.33634E-4, - 4.2494E-4, - 2.24887E-4, - 2.17664E-4, - 2.20388E-4, - 2.14184E-4, - 2.14931E-4, - 2.22858E-4, - 2.21678E-4, - 2.21808E-4, - 2.1793E-4, - 2.16118E-4, - 2.15917E-4, - 2.21341E-4, - 2.20529E-4, - 2.26088E-4, - 2.76256E-4, - 1.54925E-4, - 1.51669E-4, - 1.53364E-4, - 1.50836E-4, - 1.51073E-4, - 1.56809E-4, - 1.509E-4, - 1.51181E-4, - 1.50864E-4, - 1.51891E-4, - 1.50041E-4, - 1.50731E-4, - 1.51156E-4, - 1.51047E-4, - 1.51181E-4, - 1.51164E-4, - 1.51131E-4, - 1.53064E-4, - 1.5131E-4, - 1.51829E-4, - 1.51748E-4, - 1.50999E-4, - 1.52264E-4 - ], - [ - 4.30509E-4, - 4.31088E-4, - 2.25501E-4, - 2.21115E-4, - 2.15446E-4, - 2.22444E-4, - 2.19883E-4, - 2.20315E-4, - 2.19017E-4, - 2.18239E-4, - 2.16508E-4, - 2.16767E-4, - 2.17822E-4, - 2.17029E-4, - 2.18181E-4, - 2.19814E-4, - 3.05731E-4, - 1.56433E-4, - 1.52905E-4, - 1.5405E-4, - 1.5197E-4, - 1.51511E-4, - 1.54897E-4, - 1.51703E-4, - 1.50501E-4, - 1.50879E-4, - 1.5231E-4, - 1.50466E-4, - 1.51541E-4, - 1.51388E-4, - 1.51212E-4, - 1.50856E-4, - 1.50873E-4, - 1.5003E-4, - 1.50461E-4, - 1.523E-4, - 1.52079E-4, - 1.51277E-4, - 1.87098E-4, - 1.52115E-4 - ], - [ - 4.2105E-4, - 4.27078E-4, - 2.25541E-4, - 2.20828E-4, - 2.22206E-4, - 2.12617E-4, - 2.17591E-4, - 2.17479E-4, - 2.13776E-4, - 2.17028E-4, - 2.14738E-4, - 2.13765E-4, - 2.18875E-4, - 2.18388E-4, - 2.14951E-4, - 2.12465E-4, - 3.05972E-4, - 1.57435E-4, - 1.52371E-4, - 1.54E-4, - 1.51993E-4, - 1.51339E-4, - 1.50864E-4, - 1.52379E-4, - 1.50738E-4, - 1.51849E-4, - 1.50727E-4, - 1.51006E-4, - 1.51283E-4, - 1.50373E-4, - 1.50402E-4, - 1.66798E-4, - 1.50966E-4, - 1.50851E-4, - 1.50586E-4, - 1.50145E-4, - 1.51848E-4, - 1.51597E-4, - 1.52343E-4, - 1.51509E-4 - ], - [ - 4.2028E-4, - 4.2232E-4, - 2.221E-4, - 2.18527E-4, - 2.18995E-4, - 2.15753E-4, - 2.14495E-4, - 2.18304E-4, - 2.12229E-4, - 2.17727E-4, - 2.18181E-4, - 2.14046E-4, - 2.14084E-4, - 2.20282E-4, - 2.18294E-4, - 2.20869E-4, - 3.01397E-4, - 1.58429E-4, - 1.52419E-4, - 1.54313E-4, - 1.52092E-4, - 1.51971E-4, - 1.50716E-4, - 1.50565E-4, - 1.51498E-4, - 1.50993E-4, - 1.51807E-4, - 1.50697E-4, - 1.52131E-4, - 1.5106E-4, - 1.51042E-4, - 1.51118E-4, - 1.51914E-4, - 1.5063E-4, - 1.51197E-4, - 1.50803E-4, - 1.52086E-4, - 1.52574E-4, - 1.5139E-4, - 1.51836E-4 - ], - [ - 4.199E-4, - 4.21169E-4, - 2.27449E-4, - 2.21039E-4, - 2.12186E-4, - 2.10767E-4, - 2.09048E-4, - 2.14919E-4, - 2.13261E-4, - 2.16644E-4, - 2.15155E-4, - 2.17899E-4, - 2.15935E-4, - 2.15655E-4, - 2.20665E-4, - 2.15339E-4, - 3.32437E-4, - 1.52502E-4, - 1.49326E-4, - 1.51792E-4, - 1.47731E-4, - 1.47449E-4, - 1.53314E-4, - 1.47112E-4, - 1.47034E-4, - 1.46734E-4, - 1.4794E-4, - 1.46937E-4, - 1.47104E-4, - 1.48377E-4, - 1.47364E-4, - 1.86805E-4, - 1.47278E-4, - 1.46781E-4, - 1.4645E-4, - 1.46513E-4, - 1.48468E-4, - 1.48901E-4, - 1.48329E-4, - 1.47559E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.002571081605, - "scoreError" : 0.0010528150851568773, - "scoreConfidence" : [ - 0.0015182665198431226, - 0.0036238966901568775 - ], - "scorePercentiles" : { - "0.0" : 0.001157877, - "50.0" : 0.0011908885, - "90.0" : 0.0018675251, - "95.0" : 0.0180821838, - "99.0" : 0.0184251219, - "99.9" : 0.018575664, - "99.99" : 0.018575664, - "99.999" : 0.018575664, - "99.9999" : 0.018575664, - "100.0" : 0.018575664 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001188078, - 0.001191262, - 0.001230655, - 0.001837945, - 0.001849608, - 0.018083927, - 0.001186499, - 0.001189172, - 0.001188895, - 0.001189416, - 0.001189389, - 0.01771084, - 0.001164439, - 0.001164031, - 0.001168695, - 0.001159943, - 0.001165228, - 0.001169185, - 0.001777501, - 0.001811485, - 0.001808443, - 0.001837083, - 0.001793541, - 0.018425185, - 0.001165735, - 0.001164132, - 0.001172833, - 0.001166353, - 0.001169515, - 0.001167233, - 0.001165456, - 0.001209669, - 0.001170588, - 0.001167185, - 0.00120385, - 0.001168708, - 0.001175402, - 0.001167981, - 0.001170859, - 0.001197912 - ], - [ - 0.001165889, - 0.001172591, - 0.001206109, - 0.001833887, - 0.001867653, - 0.018339798, - 0.001167368, - 0.001166535, - 0.001167409, - 0.001165948, - 0.001161205, - 0.018201594, - 0.001164472, - 0.001165751, - 0.001165168, - 0.001167527, - 0.001169952, - 0.001165047, - 0.001808291, - 0.001803094, - 0.001797288, - 0.001840105, - 0.001795799, - 0.018192652, - 0.001159807, - 0.001201298, - 0.00116856, - 0.001166161, - 0.001168206, - 0.001170415, - 0.001158753, - 0.001165479, - 0.001166256, - 0.001218467, - 0.001196406, - 0.001161945, - 0.001192445, - 0.00119186, - 0.001193405, - 0.001191772 - ], - [ - 0.001169327, - 0.001161232, - 0.001208152, - 0.001808193, - 0.001860676, - 0.018418875, - 0.001163875, - 0.00115817, - 0.001166192, - 0.001167505, - 0.001157877, - 0.01824885, - 0.00117062, - 0.001162399, - 0.001168353, - 0.001164236, - 0.001212095, - 0.00116488, - 0.001817892, - 0.001866374, - 0.001870828, - 0.001836517, - 0.001844997, - 0.01823695, - 0.001187311, - 0.001226774, - 0.001193187, - 0.001193558, - 0.001196195, - 0.0011864, - 0.001160859, - 0.001169405, - 0.001169073, - 0.001243814, - 0.001196924, - 0.001161564, - 0.001165597, - 0.00116375, - 0.001172462, - 0.001165386 - ], - [ - 0.001195798, - 0.001192974, - 0.001256421, - 0.001843589, - 0.001877434, - 0.018047139, - 0.001192534, - 0.001187909, - 0.001194221, - 0.001194767, - 0.001186486, - 0.01782113, - 0.001188467, - 0.001164103, - 0.001169093, - 0.001168683, - 0.001167199, - 0.001170063, - 0.001797513, - 0.001814231, - 0.001791607, - 0.001804389, - 0.001824786, - 0.018575664, - 0.001161485, - 0.001164604, - 0.001172049, - 0.001170147, - 0.001168011, - 0.001161284, - 0.001161737, - 0.001249748, - 0.001168737, - 0.001167263, - 0.001195367, - 0.001163486, - 0.001170369, - 0.001167075, - 0.001169355, - 0.001167566 - ], - [ - 0.001193088, - 0.001195988, - 0.001233901, - 0.001839296, - 0.001866032, - 0.018049063, - 0.001192319, - 0.001186831, - 0.001191494, - 0.001188183, - 0.001186944, - 0.017849051, - 0.001202051, - 0.001209072, - 0.001246946, - 0.001293249, - 0.001222799, - 0.001194139, - 0.00184582, - 0.00186113, - 0.001875978, - 0.001850583, - 0.00189348, - 0.018218331, - 0.001188109, - 0.001193858, - 0.001196885, - 0.001191407, - 0.001411511, - 0.001186684, - 0.001186729, - 0.001234516, - 0.001192172, - 0.001197548, - 0.001226317, - 0.001188741, - 0.001190515, - 0.001190242, - 0.001193323, - 0.001193966 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.018934058250000007, - "scoreError" : 0.007464157084038221, - "scoreConfidence" : [ - 0.011469901165961787, - 0.026398215334038227 - ], - "scorePercentiles" : { - "0.0" : 0.010043578, - "50.0" : 0.0105508255, - "90.0" : 0.0117502443, - "95.0" : 0.13731859759999998, - "99.0" : 0.14130487378, - "99.9" : 0.143638802, - "99.99" : 0.143638802, - "99.999" : 0.143638802, - "99.9999" : 0.143638802, - "100.0" : 0.143638802 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.010890662, - 0.140151972, - 0.010657398, - 0.011262281, - 0.010181611, - 0.010309932, - 0.010883881, - 0.011285999, - 0.010169471, - 0.010443645, - 0.139052778, - 0.010695463, - 0.010379092, - 0.011118059, - 0.010507199, - 0.010121987, - 0.010501209, - 0.010243036, - 0.010517823, - 0.010369009, - 0.010513457, - 0.010043578, - 0.010339599, - 0.010442173, - 0.010432139, - 0.010443254, - 0.010272965, - 0.01046462, - 0.010170369, - 0.010635188, - 0.133373539, - 0.010627301, - 0.010526895, - 0.010356594, - 0.010402861, - 0.010064688, - 0.010460305, - 0.010449581, - 0.010669285, - 0.010318169 - ], - [ - 0.010843633, - 0.139680795, - 0.010593333, - 0.010091995, - 0.010338562, - 0.011112462, - 0.010848374, - 0.010989673, - 0.010338104, - 0.01060677, - 0.14097142, - 0.01086922, - 0.010596168, - 0.010346098, - 0.010397119, - 0.010288422, - 0.010306609, - 0.010394416, - 0.01061827, - 0.010341051, - 0.010848969, - 0.132194412, - 0.010614742, - 0.010517957, - 0.010272304, - 0.010368477, - 0.010099045, - 0.010620146, - 0.010552433, - 0.010346289, - 0.010692158, - 0.010825035, - 0.010504801, - 0.010534912, - 0.010086298, - 0.010508138, - 0.01012584, - 0.010338709, - 0.010324335, - 0.010589123 - ], - [ - 0.011099876, - 0.141308242, - 0.011918732, - 0.010611027, - 0.010669855, - 0.010947354, - 0.010988497, - 0.01102686, - 0.010172363, - 0.0108023, - 0.143638802, - 0.010511751, - 0.010653828, - 0.010368099, - 0.010554757, - 0.01034625, - 0.010568067, - 0.010867928, - 0.010486898, - 0.01055273, - 0.010423856, - 0.13615579, - 0.010352563, - 0.010378211, - 0.010476463, - 0.010666208, - 0.01018948, - 0.010556796, - 0.010626531, - 0.010496947, - 0.01036796, - 0.0104094, - 0.010377237, - 0.010280531, - 0.010360107, - 0.010543471, - 0.011018736, - 0.010303659, - 0.010500283, - 0.010408966 - ], - [ - 0.010859257, - 0.139214631, - 0.010678422, - 0.010543896, - 0.010844033, - 0.011214235, - 0.010839694, - 0.010531584, - 0.010327768, - 0.010720826, - 0.13843499, - 0.010478928, - 0.010489273, - 0.010208301, - 0.010552355, - 0.010370722, - 0.010446921, - 0.01040147, - 0.010625456, - 0.011753154, - 0.014000535, - 0.137379798, - 0.011377838, - 0.010891303, - 0.011099745, - 0.010406588, - 0.010599419, - 0.010412704, - 0.010723655, - 0.010551619, - 0.010718734, - 0.01038377, - 0.011139392, - 0.011724057, - 0.012163269, - 0.010931401, - 0.012143749, - 0.012532155, - 0.010166564, - 0.012323542 - ], - [ - 0.010849279, - 0.010812317, - 0.010602696, - 0.010371685, - 0.010468987, - 0.010635896, - 0.010897843, - 0.010550032, - 0.010604142, - 0.010489492, - 0.010391517, - 0.010685929, - 0.010514689, - 0.010682262, - 0.13829516, - 0.010594125, - 0.010476497, - 0.010255843, - 0.010603466, - 0.01064522, - 0.010520216, - 0.010617019, - 0.010488072, - 0.010939101, - 0.010710177, - 0.010400433, - 0.010795933, - 0.010459709, - 0.010554849, - 0.010279635, - 0.010491318, - 0.010431794, - 0.010343304, - 0.010881872, - 0.010554362, - 0.010591141, - 0.01040035, - 0.010429605, - 0.01042451, - 0.010592325 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.9052169500000002E-4, - "scoreError" : 2.7547829291905938E-5, - "scoreConfidence" : [ - 1.629738657080941E-4, - 2.1806952429190594E-4 - ], - "scorePercentiles" : { - "0.0" : 5.3141E-5, - "50.0" : 2.11595E-4, - "90.0" : 3.72638E-4, - "95.0" : 3.766676E-4, - "99.0" : 3.8457736E-4, - "99.9" : 3.85111E-4, - "99.99" : 3.85111E-4, - "99.999" : 3.85111E-4, - "99.9999" : 3.85111E-4, - "100.0" : 3.85111E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 3.60746E-4, - 3.67177E-4, - 3.67358E-4, - 3.7108E-4, - 3.71896E-4, - 3.74889E-4, - 3.66121E-4, - 3.74577E-4, - 2.66106E-4, - 2.39226E-4, - 2.32587E-4, - 2.09297E-4, - 2.06759E-4, - 2.09003E-4, - 2.11583E-4, - 2.23038E-4, - 2.12274E-4, - 2.11821E-4, - 2.09513E-4, - 2.09596E-4, - 2.10205E-4, - 2.12298E-4, - 2.14582E-4, - 2.0699E-4, - 2.12983E-4, - 2.07753E-4, - 5.3141E-5, - 6.1188E-5, - 5.8461E-5, - 5.7467E-5, - 5.8146E-5, - 5.9758E-5, - 1.01072E-4, - 5.8105E-5, - 6.2723E-5, - 6.0051E-5, - 6.1328E-5, - 5.3637E-5, - 5.4863E-5, - 5.5791E-5 - ], - [ - 3.65172E-4, - 3.67335E-4, - 3.6833E-4, - 3.6609E-4, - 3.7262E-4, - 3.71512E-4, - 3.64787E-4, - 3.77097E-4, - 2.54396E-4, - 2.38001E-4, - 2.38525E-4, - 2.15279E-4, - 2.13404E-4, - 2.14338E-4, - 2.09323E-4, - 2.21139E-4, - 2.14328E-4, - 2.12972E-4, - 2.16617E-4, - 2.13395E-4, - 2.1268E-4, - 2.09735E-4, - 2.08471E-4, - 2.09817E-4, - 2.13448E-4, - 5.8257E-5, - 5.5265E-5, - 5.9269E-5, - 5.7324E-5, - 7.15E-5, - 5.593E-5, - 5.5758E-5, - 6.2807E-5, - 5.5827E-5, - 5.4885E-5, - 5.6901E-5, - 5.7377E-5, - 5.8372E-5, - 5.6279E-5, - 5.5838E-5 - ], - [ - 3.79694E-4, - 3.85111E-4, - 3.81636E-4, - 3.76735E-4, - 3.76065E-4, - 3.77756E-4, - 3.76009E-4, - 3.82732E-4, - 2.6535E-4, - 2.43337E-4, - 2.40984E-4, - 2.1817E-4, - 2.22207E-4, - 2.16119E-4, - 2.14129E-4, - 2.28595E-4, - 2.14333E-4, - 2.17067E-4, - 2.17253E-4, - 2.17719E-4, - 2.26893E-4, - 2.1363E-4, - 2.14247E-4, - 2.21815E-4, - 2.18884E-4, - 5.7994E-5, - 6.0388E-5, - 5.9324E-5, - 5.6329E-5, - 5.7763E-5, - 5.5829E-5, - 5.7771E-5, - 5.7835E-5, - 5.9872E-5, - 5.565E-5, - 5.6268E-5, - 5.4287E-5, - 5.5521E-5, - 5.5479E-5, - 5.7642E-5 - ], - [ - 3.72588E-4, - 3.68375E-4, - 3.66744E-4, - 3.75528E-4, - 3.76451E-4, - 3.75938E-4, - 3.68161E-4, - 3.84596E-4, - 2.58794E-4, - 2.4048E-4, - 2.35542E-4, - 2.16133E-4, - 2.107E-4, - 2.12586E-4, - 2.08138E-4, - 2.24001E-4, - 2.08348E-4, - 2.0789E-4, - 2.11577E-4, - 2.17214E-4, - 2.13768E-4, - 2.17073E-4, - 2.12514E-4, - 2.10956E-4, - 2.14312E-4, - 5.689E-5, - 6.1772E-5, - 6.0345E-5, - 5.5863E-5, - 5.4377E-5, - 5.4461E-5, - 5.6986E-5, - 5.433E-5, - 5.441E-5, - 5.9089E-5, - 6.2678E-5, - 5.6693E-5, - 5.6323E-5, - 5.7283E-5, - 6.1755E-5 - ], - [ - 3.67905E-4, - 3.77365E-4, - 3.68683E-4, - 3.76489E-4, - 3.7264E-4, - 3.69392E-4, - 3.74516E-4, - 3.76677E-4, - 2.54456E-4, - 2.36135E-4, - 2.36032E-4, - 2.08606E-4, - 2.07682E-4, - 2.11607E-4, - 2.11419E-4, - 2.17608E-4, - 2.15595E-4, - 2.10668E-4, - 2.16198E-4, - 2.18802E-4, - 2.1289E-4, - 2.12323E-4, - 2.0961E-4, - 2.08193E-4, - 2.09313E-4, - 5.3953E-5, - 5.6015E-5, - 5.5414E-5, - 6.1445E-5, - 6.3981E-5, - 5.4364E-5, - 7.7555E-5, - 5.4628E-5, - 6.0446E-5, - 6.0762E-5, - 5.7906E-5, - 5.6569E-5, - 5.6267E-5, - 6.5496E-5, - 5.7061E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 7.919515550000008E-4, - "scoreError" : 6.223901722385885E-4, - "scoreConfidence" : [ - 1.6956138276141223E-4, - 0.0014143417272385892 - ], - "scorePercentiles" : { - "0.0" : 2.37854E-4, - "50.0" : 2.578155E-4, - "90.0" : 5.924103E-4, - "95.0" : 6.104163499999999E-4, - "99.0" : 0.017180825309999998, - "99.9" : 0.017547936, - "99.99" : 0.017547936, - "99.999" : 0.017547936, - "99.9999" : 0.017547936, - "100.0" : 0.017547936 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 5.79169E-4, - 5.73815E-4, - 5.74743E-4, - 5.71308E-4, - 3.33532E-4, - 2.95759E-4, - 2.42035E-4, - 2.59563E-4, - 2.39029E-4, - 2.55591E-4, - 2.43074E-4, - 2.3994E-4, - 2.42381E-4, - 2.55361E-4, - 2.42967E-4, - 2.42919E-4, - 0.017181289, - 2.45332E-4, - 2.38902E-4, - 2.41059E-4, - 2.54968E-4, - 3.35883E-4, - 2.44177E-4, - 2.42874E-4, - 2.40738E-4, - 2.56167E-4, - 2.46552E-4, - 2.44013E-4, - 2.41284E-4, - 2.38142E-4, - 3.32196E-4, - 5.8856E-4, - 5.79742E-4, - 5.77785E-4, - 5.72692E-4, - 5.84772E-4, - 5.91827E-4, - 5.97253E-4, - 5.78537E-4, - 5.81585E-4 - ], - [ - 5.84676E-4, - 5.83998E-4, - 5.82069E-4, - 5.91896E-4, - 3.35313E-4, - 3.15796E-4, - 2.54385E-4, - 2.56324E-4, - 2.52793E-4, - 2.55798E-4, - 2.38656E-4, - 2.4034E-4, - 2.39197E-4, - 2.41397E-4, - 2.41412E-4, - 2.43419E-4, - 0.01713492, - 2.61629E-4, - 2.55213E-4, - 2.42581E-4, - 2.56337E-4, - 2.52097E-4, - 2.41571E-4, - 2.57034E-4, - 2.4335E-4, - 2.62296E-4, - 2.53328E-4, - 2.45816E-4, - 2.40263E-4, - 2.44291E-4, - 3.58803E-4, - 5.94283E-4, - 6.04265E-4, - 5.73459E-4, - 6.06395E-4, - 5.8669E-4, - 5.8452E-4, - 5.88489E-4, - 5.95837E-4, - 5.93658E-4 - ], - [ - 5.81471E-4, - 5.93994E-4, - 5.63732E-4, - 5.70232E-4, - 3.61764E-4, - 3.04608E-4, - 2.40384E-4, - 2.66735E-4, - 2.38051E-4, - 2.38728E-4, - 2.39348E-4, - 2.55107E-4, - 2.5627E-4, - 2.55601E-4, - 2.42375E-4, - 4.73984E-4, - 0.016920146, - 2.48704E-4, - 2.41457E-4, - 2.42302E-4, - 2.43827E-4, - 2.57123E-4, - 3.71763E-4, - 2.43448E-4, - 2.42364E-4, - 2.58412E-4, - 2.49123E-4, - 2.44912E-4, - 2.41301E-4, - 2.44236E-4, - 3.53793E-4, - 5.82392E-4, - 5.79367E-4, - 5.91198E-4, - 5.81489E-4, - 5.75985E-4, - 5.89827E-4, - 5.82444E-4, - 5.66644E-4, - 5.95509E-4 - ], - [ - 5.87964E-4, - 5.77984E-4, - 5.64089E-4, - 5.76472E-4, - 4.62947E-4, - 2.77819E-4, - 2.52479E-4, - 2.56731E-4, - 2.38743E-4, - 2.54736E-4, - 2.39741E-4, - 2.51926E-4, - 2.52343E-4, - 2.54767E-4, - 2.40669E-4, - 2.38177E-4, - 0.017547936, - 2.78466E-4, - 2.54636E-4, - 2.57932E-4, - 2.40724E-4, - 2.6469E-4, - 2.57699E-4, - 2.38805E-4, - 2.55282E-4, - 2.39216E-4, - 2.4741E-4, - 2.54897E-4, - 2.4191E-4, - 2.55574E-4, - 5.65289E-4, - 5.8754E-4, - 5.65922E-4, - 5.78222E-4, - 5.65458E-4, - 5.81047E-4, - 5.72746E-4, - 5.73491E-4, - 5.67877E-4, - 5.80498E-4 - ], - [ - 6.10628E-4, - 6.35885E-4, - 6.11403E-4, - 6.25235E-4, - 2.87257E-4, - 2.93135E-4, - 2.41625E-4, - 2.4161E-4, - 2.39815E-4, - 2.41357E-4, - 2.40968E-4, - 2.3845E-4, - 2.56148E-4, - 2.55064E-4, - 2.42472E-4, - 2.4123E-4, - 0.017106261, - 2.63859E-4, - 2.56698E-4, - 2.57478E-4, - 2.4088E-4, - 2.4218E-4, - 2.54247E-4, - 2.56916E-4, - 2.54826E-4, - 4.79977E-4, - 2.70194E-4, - 2.60027E-4, - 2.37854E-4, - 2.56355E-4, - 3.48245E-4, - 6.12313E-4, - 5.9344E-4, - 5.87812E-4, - 5.87461E-4, - 5.81146E-4, - 5.92457E-4, - 5.90151E-4, - 5.72149E-4, - 5.9199E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.004144344479999999, - "scoreError" : 0.003119424338248426, - "scoreConfidence" : [ - 0.001024920141751573, - 0.007263768818248426 - ], - "scorePercentiles" : { - "0.0" : 0.002206665, - "50.0" : 0.0026110465, - "90.0" : 0.0057495673, - "95.0" : 0.0065984667999999976, - "99.0" : 0.00742134581, - "99.9" : 0.18900029, - "99.99" : 0.18900029, - "99.999" : 0.18900029, - "99.9999" : 0.18900029, - "100.0" : 0.18900029 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.002262267, - 0.002628417, - 0.003681065, - 0.002385086, - 0.002244276, - 0.005750807, - 0.004345829, - 0.002275, - 0.002351713, - 0.002314392, - 0.00455161, - 0.005653723, - 0.002643549, - 0.002704678, - 0.00262816, - 0.002645288, - 0.00282946, - 0.006270428, - 0.007127719, - 0.003227388, - 0.002206788, - 0.00234738, - 0.002216778, - 0.002348509, - 0.002625198, - 0.002213632, - 0.004256462, - 0.002341972, - 0.002244304, - 0.002375673, - 0.002211398, - 0.002450263, - 0.002269248, - 0.002320633, - 0.004662205, - 0.00596484, - 0.002397389, - 0.003898681, - 0.00393618, - 0.002358217 - ], - [ - 0.002466753, - 0.002493581, - 0.003173184, - 0.002389774, - 0.002376692, - 0.00576197, - 0.00385513, - 0.002400971, - 0.00248342, - 0.00226452, - 0.003558733, - 0.005521726, - 0.002740647, - 0.00286486, - 0.002630601, - 0.002636529, - 0.002513481, - 0.005552421, - 0.006119326, - 0.00355021, - 0.002215302, - 0.002223889, - 0.002220301, - 0.002442276, - 0.002612322, - 0.002372783, - 0.004189212, - 0.002383294, - 0.002223949, - 0.002248344, - 0.002256294, - 0.002570282, - 0.002394303, - 0.002276744, - 0.003193541, - 0.006123177, - 0.002639965, - 0.003015564, - 0.004137371, - 0.002216958 - ], - [ - 0.002273392, - 0.002631759, - 0.003266557, - 0.002346596, - 0.002282935, - 0.005474676, - 0.003882156, - 0.002291541, - 0.002440547, - 0.00229346, - 0.002970206, - 0.004135194, - 0.002372888, - 0.002219801, - 0.002218448, - 0.002464727, - 0.002545079, - 0.00573841, - 0.007405289, - 0.004735203, - 0.002593267, - 0.002625808, - 0.002656078, - 0.002666458, - 0.002567444, - 0.002506541, - 0.004097112, - 0.002387042, - 0.002213812, - 0.002370082, - 0.002362104, - 0.00259431, - 0.002369572, - 0.002407316, - 0.002431526, - 0.006379336, - 0.002797721, - 0.002938148, - 0.007344875, - 0.002394328 - ], - [ - 0.002501285, - 0.002310605, - 0.003683124, - 0.002287606, - 0.002222295, - 0.005771337, - 0.003612682, - 0.002506957, - 0.00241991, - 0.002326161, - 0.002698688, - 0.18900029, - 0.002234404, - 0.002360535, - 0.00232246, - 0.002259736, - 0.002477597, - 0.005676528, - 0.00661, - 0.004600242, - 0.002561841, - 0.002801411, - 0.002642838, - 0.002528224, - 0.002561247, - 0.002297108, - 0.004165432, - 0.002385132, - 0.002206665, - 0.002381108, - 0.002986947, - 0.002822636, - 0.002534991, - 0.002634864, - 0.002550625, - 0.005710169, - 0.003011942, - 0.006866306, - 0.007123112, - 0.00245847 - ], - [ - 0.002474574, - 0.002526883, - 0.00328726, - 0.002251801, - 0.002328413, - 0.006028199, - 0.003674762, - 0.00242738, - 0.002266154, - 0.002583256, - 0.002928467, - 0.005442842, - 0.002788584, - 0.002690464, - 0.002651459, - 0.002805371, - 0.002735269, - 0.007319739, - 0.007421508, - 0.004590612, - 0.002733468, - 0.002824289, - 0.002625477, - 0.002569264, - 0.002650283, - 0.002452617, - 0.005445862, - 0.002612008, - 0.002675603, - 0.002832361, - 0.002843605, - 0.002610085, - 0.002500805, - 0.002386464, - 0.002384479, - 0.005878867, - 0.0030155, - 0.003474235, - 0.007292458, - 0.00255591 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.take", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.460003780135, - "scoreError" : 0.2372513992373334, - "scoreConfidence" : [ - 0.22275238089766658, - 0.6972551793723334 - ], - "scorePercentiles" : { - "0.0" : 0.023200632, - "50.0" : 0.0260964485, - "90.0" : 1.7662338435, - "95.0" : 2.4836163858499996, - "99.0" : 4.856327799870003, - "99.9" : 5.014103322, - "99.99" : 5.014103322, - "99.999" : 5.014103322, - "99.9999" : 5.014103322, - "100.0" : 5.014103322 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.025135005, - 0.033465488, - 0.024857311, - 0.02492689, - 0.034385502, - 0.025003503, - 1.364798848, - 2.338667653, - 1.735159095, - 0.027108967, - 0.026209806, - 0.024536683, - 0.024917452, - 0.033903174, - 0.023797908, - 0.025002536, - 0.029124043, - 4.052022169, - 1.592580669, - 0.023942734, - 0.025283336, - 0.027176785, - 0.0249701, - 0.024309351, - 0.025077728, - 0.034659918, - 0.026362051, - 0.02448573, - 1.416744514, - 2.450618881, - 1.761972492, - 0.026288805, - 0.025001047, - 0.030125583, - 0.02488333, - 0.023717047, - 0.024042201, - 0.031057362, - 0.024267377, - 4.17186011 - ], - [ - 0.037861315, - 0.02526194, - 0.025940166, - 0.030071024, - 0.024820272, - 0.024433422, - 0.031624083, - 0.025228023, - 1.303062954, - 2.290713074, - 1.655305723, - 0.025344335, - 0.025724, - 0.02496371, - 0.02686097, - 0.032778189, - 0.023627056, - 0.024888355, - 0.029996588, - 0.024999779, - 4.441392057, - 1.663619313, - 0.023768381, - 0.026909655, - 0.028853253, - 0.025178453, - 0.023666705, - 0.026230357, - 0.032626488, - 0.024551603, - 3.868308562, - 1.569222713, - 1.666615424, - 0.024693246, - 0.023756954, - 0.025680779, - 0.02981733, - 0.024812304, - 0.023598908, - 0.024929314 - ], - [ - 0.038293636, - 0.023200632, - 0.024991227, - 0.032851745, - 0.026013211, - 0.024976407, - 0.032808954, - 0.024776518, - 0.025137443, - 2.142189244, - 5.014103322, - 0.028812147, - 0.024531851, - 0.024995596, - 0.031077829, - 0.024960899, - 0.024089807, - 0.032668975, - 0.024937861, - 0.025581829, - 1.5691347, - 2.554014967, - 0.026121495, - 0.024486979, - 0.024116193, - 0.023567849, - 0.024909399, - 0.03541515, - 0.024166147, - 0.025375051, - 0.025114686, - 2.08411544, - 2.473512449, - 0.024736377, - 0.02746773, - 0.025497245, - 0.023840137, - 0.024800958, - 0.033905253, - 0.027147702 - ], - [ - 0.042132738, - 0.026071402, - 0.027115027, - 0.031885224, - 0.024000123, - 0.024889513, - 0.031348771, - 0.025085403, - 1.281877909, - 2.231596079, - 1.689872643, - 0.02531562, - 0.026682022, - 0.023922738, - 0.024917184, - 0.033886562, - 0.024593199, - 0.024864707, - 0.029376442, - 1.804205775, - 3.84911276, - 1.703671453, - 0.023985019, - 0.027145049, - 0.028780904, - 0.023621643, - 0.024308906, - 0.025239984, - 0.032758891, - 0.025493383, - 0.024220569, - 1.530824265, - 1.657561004, - 0.024006061, - 0.02624767, - 0.02682613, - 0.032415213, - 0.024269372, - 0.024731897, - 0.025154065 - ], - [ - 0.037693408, - 0.027188227, - 0.025582912, - 0.03157872, - 0.023648565, - 0.025133045, - 0.031864789, - 0.026530352, - 0.024773714, - 2.116632792, - 4.86051907, - 0.027911705, - 0.024139274, - 0.025434202, - 0.029711926, - 0.026188593, - 0.025419472, - 0.032057549, - 0.024120565, - 0.024937626, - 1.490264903, - 2.484148172, - 1.766707327, - 0.027162333, - 0.027033083, - 0.024470158, - 0.023684642, - 0.024909488, - 0.038947022, - 0.024302864, - 0.025002225, - 1.498058832, - 2.495217078, - 0.02619442, - 0.025033964, - 0.029717561, - 0.025233283, - 0.024412055, - 0.025141582, - 0.033404209 - ] - ] - }, - "secondaryMetrics" : { - } - } -] - - diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.png b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.png deleted file mode 100644 index 1baef7b7b57e4a378fe5ec1b274cf5e6c00d9480..0000000000000000000000000000000000000000 Binary files a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_drop.png and /dev/null differ diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.json b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.json deleted file mode 100644 index 281eaae253e48aa9cb71bce1d91c061a922cc133..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.json +++ /dev/null @@ -1,4132 +0,0 @@ -[ - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.3138780000000006E-5, - "scoreError" : 1.528127842192391E-6, - "scoreConfidence" : [ - 1.1610652157807614E-5, - 1.4666907842192397E-5 - ], - "scorePercentiles" : { - "0.0" : 6.417E-6, - "50.0" : 1.0846499999999999E-5, - "90.0" : 2.1913700000000007E-5, - "95.0" : 3.0361999999999964E-5, - "99.0" : 3.877779000000002E-5, - "99.9" : 4.271E-5, - "99.99" : 4.271E-5, - "99.999" : 4.271E-5, - "99.9999" : 4.271E-5, - "100.0" : 4.271E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.0306E-5, - 9.856E-6, - 9.549E-6, - 9.725E-6, - 8.996E-6, - 9.291E-6, - 9.531E-6, - 9.606E-6, - 1.0886E-5, - 1.1025E-5, - 1.0233E-5, - 1.0611E-5, - 1.452E-5, - 1.0263E-5, - 1.4691E-5, - 1.075E-5, - 1.4091E-5, - 1.3805E-5, - 9.645E-6, - 1.3027E-5, - 1.5055E-5, - 9.623E-6, - 1.0055E-5, - 9.553E-6, - 9.76E-6, - 8.182E-6, - 7.954E-6, - 9.106E-6, - 1.0187E-5, - 8.079E-6, - 8.994E-6, - 8.199E-6, - 8.628E-6, - 1.0725E-5, - 9.59E-6, - 8.075E-6, - 1.2181E-5, - 4.271E-5, - 9.506E-6, - 1.4042E-5 - ], - [ - 1.433E-5, - 1.4074E-5, - 1.5759E-5, - 1.1535E-5, - 1.0959E-5, - 1.4021E-5, - 1.452E-5, - 1.6772E-5, - 1.0264E-5, - 1.4797E-5, - 1.075E-5, - 1.6043E-5, - 2.7417E-5, - 1.5585E-5, - 3.0517E-5, - 1.1777E-5, - 1.1615E-5, - 3.1193E-5, - 3.3444E-5, - 1.2913E-5, - 1.5243E-5, - 3.7173E-5, - 9.412E-6, - 1.0145E-5, - 3.6325E-5, - 7.672E-6, - 7.176E-6, - 9.216E-6, - 3.4192E-5, - 1.3987E-5, - 2.2034E-5, - 7.566E-6, - 7.717E-6, - 1.0716E-5, - 1.0879E-5, - 2.2625E-5, - 1.2431E-5, - 2.0191E-5, - 1.133E-5, - 1.108E-5 - ], - [ - 1.8399E-5, - 1.8937E-5, - 2.0831E-5, - 1.863E-5, - 1.2124E-5, - 1.6012E-5, - 1.4496E-5, - 1.359E-5, - 1.2414E-5, - 1.3463E-5, - 1.3907E-5, - 1.7746E-5, - 1.6589E-5, - 1.1352E-5, - 1.1967E-5, - 1.1069E-5, - 1.5535E-5, - 2.7037E-5, - 1.3044E-5, - 1.2464E-5, - 2.454E-5, - 1.1621E-5, - 1.6172E-5, - 1.2906E-5, - 1.3601E-5, - 2.2422E-5, - 1.1522E-5, - 1.2671E-5, - 1.7785E-5, - 1.3904E-5, - 1.422E-5, - 1.4986E-5, - 1.4666E-5, - 1.4135E-5, - 1.2964E-5, - 1.5253E-5, - 1.4946E-5, - 2.3892E-5, - 1.3321E-5, - 1.2976E-5 - ], - [ - 1.0836E-5, - 9.783E-6, - 9.625E-6, - 9.758E-6, - 9.362E-6, - 9.159E-6, - 1.0604E-5, - 9.923E-6, - 9.577E-6, - 8.597E-6, - 9.215E-6, - 1.0216E-5, - 3.239E-5, - 1.0253E-5, - 1.062E-5, - 1.0587E-5, - 1.0857E-5, - 1.1998E-5, - 2.3706E-5, - 9.751E-6, - 1.5493E-5, - 9.656E-6, - 9.869E-6, - 2.5335E-5, - 8.625E-6, - 7.898E-6, - 2.2052E-5, - 3.5788E-5, - 9.673E-6, - 8.262E-6, - 8.042E-6, - 7.949E-6, - 7.327E-6, - 6.783E-6, - 6.417E-6, - 7.957E-6, - 8.223E-6, - 1.261E-5, - 7.431E-6, - 8.913E-6 - ], - [ - 1.181E-5, - 1.0401E-5, - 9.595E-6, - 1.0438E-5, - 9.703E-6, - 9.85E-6, - 1.1082E-5, - 1.0794E-5, - 1.1058E-5, - 1.1085E-5, - 1.018E-5, - 1.008E-5, - 1.0231E-5, - 9.602E-6, - 9.811E-6, - 9.628E-6, - 1.082E-5, - 1.139E-5, - 3.8794E-5, - 9.979E-6, - 1.7579E-5, - 1.3581E-5, - 1.0044E-5, - 9.086E-6, - 8.007E-6, - 7.865E-6, - 7.832E-6, - 7.794E-6, - 7.127E-6, - 1.1444E-5, - 1.0192E-5, - 8.82E-6, - 7.868E-6, - 7.727E-6, - 1.0464E-5, - 9.907E-6, - 9.264E-6, - 1.4598E-5, - 8.577E-6, - 8.414E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.1416414999999992E-5, - "scoreError" : 1.014676800120889E-6, - "scoreConfidence" : [ - 1.0401738199879103E-5, - 1.2431091800120882E-5 - ], - "scorePercentiles" : { - "0.0" : 6.331E-6, - "50.0" : 1.04425E-5, - "90.0" : 1.61839E-5, - "95.0" : 1.8340299999999998E-5, - "99.0" : 3.658052000000006E-5, - "99.9" : 4.0758E-5, - "99.99" : 4.0758E-5, - "99.999" : 4.0758E-5, - "99.9999" : 4.0758E-5, - "100.0" : 4.0758E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.6654E-5, - 1.3017E-5, - 1.1719E-5, - 1.1473E-5, - 1.2789E-5, - 1.7562E-5, - 1.1402E-5, - 1.0957E-5, - 1.1022E-5, - 1.0857E-5, - 1.9211E-5, - 1.0053E-5, - 8.794E-6, - 1.4189E-5, - 8.799E-6, - 8.428E-6, - 8.875E-6, - 1.5506E-5, - 1.2279E-5, - 1.0776E-5, - 1.0253E-5, - 1.0816E-5, - 9.789E-6, - 8.917E-6, - 9.142E-6, - 1.0466E-5, - 9.732E-6, - 9.131E-6, - 9.337E-6, - 9.131E-6, - 9.259E-6, - 2.0806E-5, - 9.287E-6, - 1.297E-5, - 1.6724E-5, - 6.561E-6, - 6.727E-6, - 1.3086E-5, - 7.039E-6, - 6.768E-6 - ], - [ - 1.3694E-5, - 1.2035E-5, - 1.2569E-5, - 1.1748E-5, - 1.1688E-5, - 1.8348E-5, - 1.0778E-5, - 1.0423E-5, - 1.0763E-5, - 1.0834E-5, - 1.87E-5, - 1.0053E-5, - 9.602E-6, - 1.6502E-5, - 1.006E-5, - 1.0053E-5, - 1.0125E-5, - 1.9536E-5, - 1.1442E-5, - 1.434E-5, - 1.0998E-5, - 1.1131E-5, - 1.0462E-5, - 1.0604E-5, - 9.104E-6, - 9.271E-6, - 9.19E-6, - 8.833E-6, - 8.281E-6, - 8.246E-6, - 8.847E-6, - 1.5516E-5, - 9.373E-6, - 1.3942E-5, - 8.46E-6, - 1.5949E-5, - 6.548E-6, - 1.1795E-5, - 7.333E-6, - 6.785E-6 - ], - [ - 1.5676E-5, - 1.1669E-5, - 1.1585E-5, - 1.0984E-5, - 1.1836E-5, - 1.6963E-5, - 1.1479E-5, - 1.1389E-5, - 1.0249E-5, - 1.0889E-5, - 1.919E-5, - 9.701E-6, - 8.523E-6, - 1.5889E-5, - 8.579E-6, - 9.033E-6, - 8.968E-6, - 1.621E-5, - 1.2278E-5, - 1.2375E-5, - 1.3013E-5, - 1.3077E-5, - 1.097E-5, - 9.595E-6, - 8.89E-6, - 1.0333E-5, - 9.281E-6, - 8.809E-6, - 8.543E-6, - 8.466E-6, - 8.679E-6, - 3.6649E-5, - 8.804E-6, - 1.3674E-5, - 8.851E-6, - 1.7827E-5, - 6.865E-6, - 1.1414E-5, - 7.07E-6, - 6.331E-6 - ], - [ - 1.3575E-5, - 1.2263E-5, - 1.2486E-5, - 1.1627E-5, - 1.1402E-5, - 1.8194E-5, - 1.1049E-5, - 1.2736E-5, - 1.0321E-5, - 1.0403E-5, - 1.9206E-5, - 1.1677E-5, - 8.518E-6, - 1.4557E-5, - 8.344E-6, - 1.0052E-5, - 8.284E-6, - 2.9801E-5, - 1.3209E-5, - 1.0858E-5, - 1.187E-5, - 1.21E-5, - 9.484E-6, - 1.0836E-5, - 8.927E-6, - 8.457E-6, - 8.169E-6, - 8.153E-6, - 8.491E-6, - 8.244E-6, - 9.443E-6, - 4.0758E-5, - 9.821E-6, - 1.5875E-5, - 7.868E-6, - 1.5702E-5, - 7.29E-6, - 1.1847E-5, - 6.395E-6, - 6.682E-6 - ], - [ - 1.4617E-5, - 1.1494E-5, - 1.2513E-5, - 1.2272E-5, - 1.2321E-5, - 1.1178E-5, - 1.053E-5, - 9.885E-6, - 9.174E-6, - 8.963E-6, - 9.52E-6, - 9.518E-6, - 9.188E-6, - 1.5553E-5, - 8.849E-6, - 9.332E-6, - 8.904E-6, - 1.483E-5, - 1.3121E-5, - 1.0955E-5, - 1.0317E-5, - 9.472E-6, - 9.188E-6, - 9.114E-6, - 9.825E-6, - 8.84E-6, - 9.089E-6, - 8.939E-6, - 8.698E-6, - 8.959E-6, - 8.458E-6, - 1.753E-5, - 8.547E-6, - 1.4813E-5, - 1.6901E-5, - 6.454E-6, - 8.099E-6, - 1.2578E-5, - 7.504E-6, - 7.397E-6 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 1.7079950000000002E-5, - "scoreError" : 1.533958144309828E-6, - "scoreConfidence" : [ - 1.5545991855690175E-5, - 1.861390814430983E-5 - ], - "scorePercentiles" : { - "0.0" : 8.727E-6, - "50.0" : 1.6804E-5, - "90.0" : 2.2987900000000004E-5, - "95.0" : 2.7795449999999978E-5, - "99.0" : 4.326946000000005E-5, - "99.9" : 6.49E-5, - "99.99" : 6.49E-5, - "99.999" : 6.49E-5, - "99.9999" : 6.49E-5, - "100.0" : 6.49E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.865E-5, - 1.4176E-5, - 1.2085E-5, - 1.985E-5, - 1.8564E-5, - 2.0125E-5, - 1.7305E-5, - 1.2902E-5, - 1.2124E-5, - 1.2728E-5, - 2.1187E-5, - 1.712E-5, - 2.0204E-5, - 2.3808E-5, - 1.2106E-5, - 9.674E-6, - 1.3812E-5, - 1.1189E-5, - 1.078E-5, - 1.6107E-5, - 1.6141E-5, - 1.634E-5, - 1.6702E-5, - 1.7796E-5, - 2.8103E-5, - 1.7964E-5, - 1.8142E-5, - 1.8601E-5, - 1.8233E-5, - 1.2647E-5, - 1.0267E-5, - 2.8344E-5, - 6.49E-5, - 1.0525E-5, - 1.0465E-5, - 1.7655E-5, - 2.4205E-5, - 3.0908E-5, - 1.2201E-5, - 1.9579E-5 - ], - [ - 1.8915E-5, - 1.9728E-5, - 2.7886E-5, - 1.681E-5, - 2.2082E-5, - 1.9644E-5, - 1.7536E-5, - 1.3776E-5, - 1.5386E-5, - 1.2743E-5, - 3.3006E-5, - 1.8311E-5, - 1.5069E-5, - 2.3226E-5, - 1.099E-5, - 1.0257E-5, - 1.8135E-5, - 1.1136E-5, - 1.3838E-5, - 1.9804E-5, - 1.4276E-5, - 1.7409E-5, - 1.7645E-5, - 1.9279E-5, - 2.171E-5, - 1.9192E-5, - 1.7333E-5, - 1.7551E-5, - 1.8161E-5, - 1.2162E-5, - 9.588E-6, - 1.8601E-5, - 2.1937E-5, - 1.0501E-5, - 1.0836E-5, - 1.9379E-5, - 1.5538E-5, - 2.0169E-5, - 1.1876E-5, - 2.2114E-5 - ], - [ - 2.0445E-5, - 1.4899E-5, - 1.8062E-5, - 2.1044E-5, - 1.9048E-5, - 1.9583E-5, - 1.6992E-5, - 1.2378E-5, - 1.2473E-5, - 1.3341E-5, - 2.0901E-5, - 1.5406E-5, - 1.869E-5, - 2.2447E-5, - 1.096E-5, - 9.352E-6, - 1.3414E-5, - 1.0932E-5, - 1.0431E-5, - 1.5892E-5, - 1.6572E-5, - 1.6655E-5, - 1.9955E-5, - 1.5727E-5, - 2.6068E-5, - 1.8046E-5, - 1.8818E-5, - 1.6798E-5, - 1.1591E-5, - 1.1544E-5, - 1.0005E-5, - 1.8357E-5, - 1.6075E-5, - 9.906E-6, - 8.727E-6, - 1.7084E-5, - 3.7672E-5, - 2.6075E-5, - 1.0989E-5, - 1.8849E-5 - ], - [ - 2.4467E-5, - 1.9172E-5, - 1.3165E-5, - 1.1442E-5, - 1.7395E-5, - 1.8077E-5, - 1.8158E-5, - 1.448E-5, - 1.293E-5, - 1.8391E-5, - 3.4903E-5, - 1.1582E-5, - 1.0108E-5, - 2.0751E-5, - 1.1295E-5, - 9.838E-6, - 1.5063E-5, - 1.5686E-5, - 1.5577E-5, - 1.328E-5, - 1.1568E-5, - 1.4959E-5, - 2.145E-5, - 1.65E-5, - 1.9852E-5, - 1.9204E-5, - 2.5608E-5, - 1.9705E-5, - 1.2544E-5, - 1.3588E-5, - 1.2074E-5, - 4.3326E-5, - 3.7287E-5, - 1.4171E-5, - 1.0878E-5, - 1.0789E-5, - 1.2042E-5, - 2.0437E-5, - 8.902E-6, - 1.9202E-5 - ], - [ - 2.0716E-5, - 1.3362E-5, - 1.316E-5, - 2.1045E-5, - 1.7549E-5, - 2.3048E-5, - 1.9364E-5, - 1.4374E-5, - 1.9262E-5, - 1.7986E-5, - 2.1837E-5, - 1.0662E-5, - 9.555E-6, - 2.3244E-5, - 9.565E-6, - 9.179E-6, - 1.5604E-5, - 1.1877E-5, - 1.0271E-5, - 9.376E-6, - 1.7637E-5, - 1.6278E-5, - 1.5403E-5, - 1.7018E-5, - 2.383E-5, - 1.8466E-5, - 2.1881E-5, - 1.5502E-5, - 1.5892E-5, - 1.6405E-5, - 1.0665E-5, - 2.0993E-5, - 1.7465E-5, - 1.7627E-5, - 1.5455E-5, - 1.1864E-5, - 9.329E-6, - 2.104E-5, - 1.354E-5, - 1.8866E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 2.3917775000000005E-5, - "scoreError" : 2.491666467469601E-6, - "scoreConfidence" : [ - 2.1426108532530403E-5, - 2.6409441467469607E-5 - ], - "scorePercentiles" : { - "0.0" : 1.1722E-5, - "50.0" : 1.97965E-5, - "90.0" : 3.643310000000001E-5, - "95.0" : 4.9687699999999995E-5, - "99.0" : 6.900151000000005E-5, - "99.9" : 7.0315E-5, - "99.99" : 7.0315E-5, - "99.999" : 7.0315E-5, - "99.9999" : 7.0315E-5, - "100.0" : 7.0315E-5 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.0593E-5, - 1.8681E-5, - 5.6965E-5, - 1.5403E-5, - 1.7759E-5, - 1.7654E-5, - 1.5704E-5, - 2.146E-5, - 4.0335E-5, - 1.7464E-5, - 2.6358E-5, - 1.3725E-5, - 1.7096E-5, - 1.3922E-5, - 1.8184E-5, - 2.261E-5, - 1.8253E-5, - 3.3349E-5, - 2.5654E-5, - 1.7554E-5, - 2.185E-5, - 1.7867E-5, - 1.2473E-5, - 4.9703E-5, - 1.9212E-5, - 2.717E-5, - 3.1677E-5, - 1.3409E-5, - 1.7809E-5, - 1.7148E-5, - 1.7418E-5, - 1.4257E-5, - 2.1667E-5, - 1.7816E-5, - 2.0151E-5, - 1.7644E-5, - 2.2059E-5, - 3.2066E-5, - 1.1722E-5, - 7.0315E-5 - ], - [ - 2.1382E-5, - 1.9227E-5, - 3.6581E-5, - 1.8911E-5, - 1.894E-5, - 2.7913E-5, - 1.9728E-5, - 2.3467E-5, - 1.7583E-5, - 2.0011E-5, - 2.6784E-5, - 1.3342E-5, - 5.0709E-5, - 1.7694E-5, - 1.4105E-5, - 1.7017E-5, - 1.4893E-5, - 1.7828E-5, - 1.4153E-5, - 2.5573E-5, - 1.8265E-5, - 1.3049E-5, - 1.7475E-5, - 4.5301E-5, - 3.1149E-5, - 2.5455E-5, - 3.458E-5, - 1.756E-5, - 2.097E-5, - 3.1833E-5, - 1.9236E-5, - 1.8219E-5, - 2.1735E-5, - 2.4847E-5, - 1.7501E-5, - 1.7259E-5, - 1.7074E-5, - 4.8644E-5, - 1.8588E-5, - 5.6464E-5 - ], - [ - 2.1407E-5, - 1.9064E-5, - 1.9948E-5, - 2.0065E-5, - 2.4212E-5, - 1.9004E-5, - 1.9788E-5, - 2.5098E-5, - 1.7104E-5, - 2.1445E-5, - 2.6279E-5, - 1.9397E-5, - 1.8535E-5, - 1.8057E-5, - 2.664E-5, - 1.8779E-5, - 2.0885E-5, - 1.8154E-5, - 1.3421E-5, - 1.928E-5, - 1.7229E-5, - 2.5607E-5, - 1.8135E-5, - 4.6308E-5, - 3.1053E-5, - 1.5233E-5, - 4.0409E-5, - 2.0336E-5, - 2.0828E-5, - 1.7164E-5, - 2.105E-5, - 1.7019E-5, - 4.2102E-5, - 1.776E-5, - 6.2518E-5, - 1.8331E-5, - 1.908E-5, - 6.9067E-5, - 1.7986E-5, - 5.1456E-5 - ], - [ - 2.0053E-5, - 1.8458E-5, - 5.8445E-5, - 2.1644E-5, - 1.9418E-5, - 1.9302E-5, - 2.2805E-5, - 1.9617E-5, - 1.9696E-5, - 2.4858E-5, - 2.7035E-5, - 2.5537E-5, - 1.9186E-5, - 2.968E-5, - 1.6965E-5, - 2.5135E-5, - 1.8229E-5, - 2.5491E-5, - 2.15E-5, - 1.91E-5, - 2.4663E-5, - 1.7372E-5, - 1.8933E-5, - 3.1951E-5, - 4.3288E-5, - 1.8748E-5, - 3.4067E-5, - 1.6063E-5, - 1.7276E-5, - 1.9508E-5, - 5.0394E-5, - 1.924E-5, - 1.8309E-5, - 2.1459E-5, - 2.4065E-5, - 1.724E-5, - 2.2478E-5, - 3.2269E-5, - 2.0226E-5, - 3.1833E-5 - ], - [ - 2.1356E-5, - 2.0004E-5, - 1.9901E-5, - 1.8612E-5, - 2.336E-5, - 1.8935E-5, - 1.9187E-5, - 2.5302E-5, - 1.8099E-5, - 3.1867E-5, - 2.6812E-5, - 2.4233E-5, - 1.7695E-5, - 1.7378E-5, - 3.5102E-5, - 1.7825E-5, - 2.3458E-5, - 1.942E-5, - 2.3688E-5, - 3.0584E-5, - 1.8507E-5, - 1.9984E-5, - 1.9354E-5, - 4.9397E-5, - 3.2538E-5, - 2.4161E-5, - 3.0751E-5, - 2.1821E-5, - 2.4078E-5, - 1.7775E-5, - 1.7291E-5, - 1.744E-5, - 1.8535E-5, - 1.7396E-5, - 1.9805E-5, - 2.4431E-5, - 1.7789E-5, - 3.3048E-5, - 1.7298E-5, - 4.9368E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.5085647500000002E-4, - "scoreError" : 1.6283513321888603E-5, - "scoreConfidence" : [ - 1.3457296167811142E-4, - 1.6713998832188862E-4 - ], - "scorePercentiles" : { - "0.0" : 5.9937E-5, - "50.0" : 1.507215E-4, - "90.0" : 2.4143620000000002E-4, - "95.0" : 2.7323774999999994E-4, - "99.0" : 3.462359500000002E-4, - "99.9" : 3.74866E-4, - "99.99" : 3.74866E-4, - "99.999" : 3.74866E-4, - "99.9999" : 3.74866E-4, - "100.0" : 3.74866E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.96103E-4, - 2.90326E-4, - 3.74866E-4, - 2.32002E-4, - 2.23338E-4, - 2.59337E-4, - 3.27718E-4, - 2.51324E-4, - 2.30297E-4, - 2.226E-4, - 2.15695E-4, - 2.84352E-4, - 2.69661E-4, - 2.894E-4, - 3.46423E-4, - 2.91646E-4, - 2.73426E-4, - 9.4104E-5, - 9.5189E-5, - 9.5513E-5, - 1.57373E-4, - 1.09877E-4, - 1.09571E-4, - 1.22852E-4, - 1.02446E-4, - 1.45621E-4, - 1.05996E-4, - 9.8675E-5, - 8.8976E-5, - 1.57332E-4, - 9.5813E-5, - 1.45647E-4, - 1.58024E-4, - 1.24387E-4, - 1.6942E-4, - 2.13988E-4, - 1.96796E-4, - 1.03669E-4, - 9.7939E-5, - 1.21009E-4 - ], - [ - 2.50161E-4, - 2.41946E-4, - 2.15894E-4, - 2.2472E-4, - 2.31422E-4, - 2.42668E-4, - 2.36848E-4, - 2.30434E-4, - 2.36251E-4, - 2.12868E-4, - 2.23064E-4, - 2.29196E-4, - 2.13802E-4, - 2.09846E-4, - 2.12585E-4, - 2.12838E-4, - 2.13157E-4, - 2.10605E-4, - 2.13486E-4, - 2.18151E-4, - 1.05701E-4, - 8.9845E-5, - 8.7E-5, - 9.1508E-5, - 9.0274E-5, - 8.4287E-5, - 9.7987E-5, - 9.667E-5, - 1.25444E-4, - 1.21743E-4, - 1.05537E-4, - 1.37435E-4, - 1.08287E-4, - 1.33981E-4, - 1.50147E-4, - 9.6558E-5, - 9.3621E-5, - 1.3326E-4, - 1.91238E-4, - 1.17037E-4 - ], - [ - 1.73246E-4, - 2.44601E-4, - 1.56392E-4, - 1.54849E-4, - 1.6071E-4, - 1.55554E-4, - 1.51201E-4, - 1.6041E-4, - 1.53309E-4, - 1.55217E-4, - 1.56053E-4, - 1.58912E-4, - 1.78742E-4, - 1.51613E-4, - 1.57757E-4, - 1.63444E-4, - 1.58163E-4, - 1.58691E-4, - 1.58962E-4, - 1.8399E-4, - 1.26128E-4, - 8.2229E-5, - 8.7124E-5, - 7.498E-5, - 7.1764E-5, - 1.1595E-4, - 6.632E-5, - 6.8115E-5, - 7.4938E-5, - 7.3374E-5, - 6.6485E-5, - 6.3362E-5, - 8.3412E-5, - 7.6246E-5, - 7.001E-5, - 6.4219E-5, - 6.4356E-5, - 6.5763E-5, - 6.5361E-5, - 6.5861E-5 - ], - [ - 2.28794E-4, - 2.34452E-4, - 2.15049E-4, - 2.22805E-4, - 2.17585E-4, - 2.09449E-4, - 2.12791E-4, - 2.15361E-4, - 2.67857E-4, - 2.34641E-4, - 2.11472E-4, - 2.10566E-4, - 2.05891E-4, - 2.24691E-4, - 2.29126E-4, - 2.21972E-4, - 2.2198E-4, - 2.45092E-4, - 2.50872E-4, - 1.14456E-4, - 1.1933E-4, - 1.00829E-4, - 9.0625E-5, - 9.16E-5, - 9.7443E-5, - 8.442E-5, - 9.2121E-5, - 1.07537E-4, - 1.08067E-4, - 1.04526E-4, - 1.0541E-4, - 1.42499E-4, - 1.0336E-4, - 1.06752E-4, - 9.0864E-5, - 8.7182E-5, - 9.629E-5, - 1.00735E-4, - 8.4317E-5, - 8.6513E-5 - ], - [ - 1.77265E-4, - 2.79867E-4, - 1.53898E-4, - 1.52042E-4, - 1.53111E-4, - 1.50489E-4, - 1.55037E-4, - 1.97783E-4, - 1.50192E-4, - 1.60868E-4, - 1.50954E-4, - 1.58274E-4, - 1.49605E-4, - 1.51062E-4, - 1.54843E-4, - 1.51172E-4, - 1.5676E-4, - 1.59973E-4, - 1.55097E-4, - 1.5654E-4, - 1.25145E-4, - 6.3165E-5, - 5.9937E-5, - 6.71E-5, - 6.1031E-5, - 6.4034E-5, - 6.329E-5, - 6.0872E-5, - 6.1405E-5, - 6.0613E-5, - 6.2358E-5, - 6.1443E-5, - 6.322E-5, - 6.2912E-5, - 9.8491E-5, - 6.4123E-5, - 6.1754E-5, - 6.7506E-5, - 6.7134E-5, - 6.1562E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 2.59396075E-4, - "scoreError" : 3.083245950291946E-5, - "scoreConfidence" : [ - 2.2856361549708054E-4, - 2.902285345029194E-4 - ], - "scorePercentiles" : { - "0.0" : 1.70802E-4, - "50.0" : 1.82025E-4, - "90.0" : 4.82823E-4, - "95.0" : 4.9065655E-4, - "99.0" : 5.067418599999999E-4, - "99.9" : 5.0721E-4, - "99.99" : 5.0721E-4, - "99.999" : 5.0721E-4, - "99.9999" : 5.0721E-4, - "100.0" : 5.0721E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.86472E-4, - 4.893E-4, - 4.8286E-4, - 4.80597E-4, - 4.92102E-4, - 4.92938E-4, - 5.05738E-4, - 5.02072E-4, - 5.0721E-4, - 4.99483E-4, - 2.01769E-4, - 1.8809E-4, - 1.89141E-4, - 1.86775E-4, - 1.84353E-4, - 1.9054E-4, - 1.83285E-4, - 1.82688E-4, - 1.81954E-4, - 1.82021E-4, - 1.87632E-4, - 1.82302E-4, - 1.8063E-4, - 1.81689E-4, - 1.8227E-4, - 1.83197E-4, - 1.82451E-4, - 1.82121E-4, - 1.8088E-4, - 1.81982E-4, - 1.81912E-4, - 2.05731E-4, - 2.36401E-4, - 1.85412E-4, - 1.83343E-4, - 1.80015E-4, - 2.17813E-4, - 1.82663E-4, - 1.82029E-4, - 1.83094E-4 - ], - [ - 4.80813E-4, - 4.7204E-4, - 4.79513E-4, - 4.72216E-4, - 4.89836E-4, - 4.90687E-4, - 5.06752E-4, - 4.95085E-4, - 4.89886E-4, - 4.85102E-4, - 2.23985E-4, - 1.78881E-4, - 1.73402E-4, - 1.77127E-4, - 1.72853E-4, - 1.7626E-4, - 1.73585E-4, - 1.71953E-4, - 1.71318E-4, - 1.83471E-4, - 1.76793E-4, - 1.73986E-4, - 1.71044E-4, - 1.7236E-4, - 1.72832E-4, - 1.75014E-4, - 1.7411E-4, - 1.72281E-4, - 1.73754E-4, - 1.71781E-4, - 1.73196E-4, - 2.19199E-4, - 1.83145E-4, - 1.72691E-4, - 1.71234E-4, - 1.7237E-4, - 1.73034E-4, - 1.73976E-4, - 2.98627E-4, - 1.76673E-4 - ], - [ - 4.87609E-4, - 4.94182E-4, - 4.73234E-4, - 4.75365E-4, - 4.7594E-4, - 4.86646E-4, - 4.82083E-4, - 4.8249E-4, - 4.79857E-4, - 4.90078E-4, - 2.66346E-4, - 1.80537E-4, - 1.74194E-4, - 1.77621E-4, - 1.75145E-4, - 1.89639E-4, - 1.74708E-4, - 1.74295E-4, - 1.78011E-4, - 1.78069E-4, - 2.3483E-4, - 1.8111E-4, - 1.7401E-4, - 1.79506E-4, - 1.78028E-4, - 1.78595E-4, - 1.80754E-4, - 1.78737E-4, - 1.80755E-4, - 1.81271E-4, - 1.83544E-4, - 1.85367E-4, - 2.24848E-4, - 1.8495E-4, - 1.86909E-4, - 1.81361E-4, - 1.79876E-4, - 1.80527E-4, - 1.77739E-4, - 1.79618E-4 - ], - [ - 4.73014E-4, - 4.85432E-4, - 4.77574E-4, - 4.78459E-4, - 4.76038E-4, - 4.76973E-4, - 4.77215E-4, - 4.70336E-4, - 4.71782E-4, - 4.81904E-4, - 1.8546E-4, - 1.76382E-4, - 1.74068E-4, - 1.75744E-4, - 1.75527E-4, - 2.20059E-4, - 1.73891E-4, - 1.7348E-4, - 1.73469E-4, - 1.73667E-4, - 2.19069E-4, - 1.71384E-4, - 1.71527E-4, - 1.74048E-4, - 1.75193E-4, - 1.73917E-4, - 1.84715E-4, - 1.77213E-4, - 2.27908E-4, - 1.72079E-4, - 1.74948E-4, - 1.9141E-4, - 2.32784E-4, - 1.78695E-4, - 1.76363E-4, - 1.76052E-4, - 1.90218E-4, - 1.91948E-4, - 1.89365E-4, - 1.74083E-4 - ], - [ - 4.7096E-4, - 4.74094E-4, - 4.71896E-4, - 4.74961E-4, - 4.70055E-4, - 4.65264E-4, - 4.72114E-4, - 4.65631E-4, - 4.68841E-4, - 4.70904E-4, - 1.85542E-4, - 1.76213E-4, - 1.77206E-4, - 1.89515E-4, - 1.71234E-4, - 1.7167E-4, - 1.7726E-4, - 1.70802E-4, - 1.72232E-4, - 1.77941E-4, - 2.16032E-4, - 1.72057E-4, - 1.73023E-4, - 1.72326E-4, - 1.79432E-4, - 1.76985E-4, - 1.75679E-4, - 1.71935E-4, - 1.73653E-4, - 1.72378E-4, - 1.73391E-4, - 2.78193E-4, - 3.42061E-4, - 1.80566E-4, - 1.76075E-4, - 1.77898E-4, - 1.74653E-4, - 1.77175E-4, - 1.78064E-4, - 1.75707E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0026458188200000005, - "scoreError" : 3.724748475858348E-4, - "scoreConfidence" : [ - 0.002273343972414166, - 0.003018293667585835 - ], - "scorePercentiles" : { - "0.0" : 0.001561146, - "50.0" : 0.0016262675, - "90.0" : 0.0049115806, - "95.0" : 0.00555910225, - "99.0" : 0.006832986540000008, - "99.9" : 0.007407361, - "99.99" : 0.007407361, - "99.999" : 0.007407361, - "99.9999" : 0.007407361, - "100.0" : 0.007407361 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001641989, - 0.004912416, - 0.004903287, - 0.001617115, - 0.001619366, - 0.001613995, - 0.001676385, - 0.001629409, - 0.00162608, - 0.001864641, - 0.001618135, - 0.001632043, - 0.004851429, - 0.005116439, - 0.005561573, - 0.005649646, - 0.001846712, - 0.00176171, - 0.001614585, - 0.001615055, - 0.001622779, - 0.001614204, - 0.001612416, - 0.00161248, - 0.004507489, - 0.001632372, - 0.001722502, - 0.001615179, - 0.001654336, - 0.001649497, - 0.001611956, - 0.001614044, - 0.001613091, - 0.001609711, - 0.002826759, - 0.004901012, - 0.005666035, - 0.005591654, - 0.005512158, - 0.005741125 - ], - [ - 0.00163345, - 0.004802275, - 0.004785467, - 0.001621456, - 0.001610303, - 0.001612834, - 0.001614965, - 0.001645905, - 0.001653464, - 0.00161203, - 0.001612382, - 0.001624008, - 0.004908265, - 0.004888519, - 0.004829976, - 0.004805187, - 0.001649555, - 0.001614817, - 0.001611951, - 0.001613486, - 0.001618236, - 0.001608243, - 0.001615133, - 0.001615379, - 0.001628312, - 0.001625681, - 0.001589984, - 0.001576798, - 0.001584208, - 0.001569824, - 0.001581784, - 0.001578142, - 0.001574592, - 0.002159507, - 0.004664558, - 0.004729665, - 0.004685121, - 0.004625908, - 0.004683018, - 0.004702209 - ], - [ - 0.001625449, - 0.004858113, - 0.007407361, - 0.001616555, - 0.001614296, - 0.001617008, - 0.001621733, - 0.001623486, - 0.001617283, - 0.001616672, - 0.00161198, - 0.001642648, - 0.005140848, - 0.005567264, - 0.005499269, - 0.005610425, - 0.001803282, - 0.001777246, - 0.001610869, - 0.001619417, - 0.001619689, - 0.001611039, - 0.001606866, - 0.001615226, - 0.001615989, - 0.001630316, - 0.001623571, - 0.001614745, - 0.001616502, - 0.001614786, - 0.001612351, - 0.001609353, - 0.001617442, - 0.001610724, - 0.003370399, - 0.004803693, - 0.004763557, - 0.004848208, - 0.006842215, - 0.005919369 - ], - [ - 0.001644044, - 0.004732261, - 0.004887935, - 0.001620162, - 0.00161723, - 0.00161233, - 0.001614257, - 0.00163061, - 0.00161835, - 0.001619528, - 0.001613228, - 0.001691423, - 0.004803902, - 0.004773331, - 0.004810127, - 0.004911949, - 0.001630546, - 0.001617261, - 0.001612901, - 0.001617071, - 0.001618758, - 0.001663554, - 0.001641042, - 0.001615507, - 0.001613841, - 0.001618242, - 0.001613297, - 0.001610104, - 0.001612195, - 0.001613323, - 0.001619444, - 0.001704985, - 0.00161015, - 0.002455064, - 0.004734826, - 0.004789269, - 0.004838491, - 0.004786511, - 0.005494829, - 0.004816777 - ], - [ - 0.001640827, - 0.004883599, - 0.00499595, - 0.001687183, - 0.001645451, - 0.00161552, - 0.001658437, - 0.001632225, - 0.001634155, - 0.001615853, - 0.001612684, - 0.001636025, - 0.004746813, - 0.004777993, - 0.004745469, - 0.004774109, - 0.001631113, - 0.001612841, - 0.001614664, - 0.001736354, - 0.00160188, - 0.001576585, - 0.001577288, - 0.001576213, - 0.001577689, - 0.001626455, - 0.001580743, - 0.001576203, - 0.001585418, - 0.001563689, - 0.001574219, - 0.001561146, - 0.001569171, - 0.0015727, - 0.002657493, - 0.004719635, - 0.005111205, - 0.004839825, - 0.004721634, - 0.005012003 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.01944036752500001, - "scoreError" : 0.0019381122121999547, - "scoreConfidence" : [ - 0.017502255312800055, - 0.021378479737199963 - ], - "scorePercentiles" : { - "0.0" : 0.01523974, - "50.0" : 0.016154019999999998, - "90.0" : 0.023280079800000002, - "95.0" : 0.046250580949999995, - "99.0" : 0.05107119785000001, - "99.9" : 0.054351501, - "99.99" : 0.054351501, - "99.999" : 0.054351501, - "99.9999" : 0.054351501, - "100.0" : 0.054351501 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.023285255, - 0.019056768, - 0.016776287, - 0.049765291, - 0.023015583, - 0.019926291, - 0.018215213, - 0.016834235, - 0.016000594, - 0.015836394, - 0.046882215, - 0.020992505, - 0.016098945, - 0.015919999, - 0.017016053, - 0.016223944, - 0.016161293, - 0.01569701, - 0.015936185, - 0.051079189, - 0.02060172, - 0.017295859, - 0.016840949, - 0.01698633, - 0.026069844, - 0.016757343, - 0.016704543, - 0.016836108, - 0.016736268, - 0.018965545, - 0.016714361, - 0.016983304, - 0.016619996, - 0.01785725, - 0.021979449, - 0.01651567, - 0.016152594, - 0.016063125, - 0.016251083, - 0.015816024 - ], - [ - 0.019784133, - 0.015991615, - 0.015811729, - 0.04964564, - 0.020925672, - 0.016333648, - 0.017777693, - 0.016042455, - 0.016100485, - 0.016623085, - 0.054351501, - 0.021479846, - 0.015834385, - 0.015920176, - 0.017074862, - 0.017518005, - 0.016162474, - 0.016433867, - 0.016011741, - 0.034015804, - 0.021221246, - 0.016138216, - 0.016126501, - 0.015881345, - 0.016617567, - 0.015992622, - 0.016453851, - 0.01597812, - 0.017210091, - 0.021132102, - 0.015858972, - 0.015883547, - 0.015832342, - 0.016248872, - 0.021451876, - 0.01616388, - 0.015888662, - 0.016032366, - 0.016101763, - 0.015950045 - ], - [ - 0.019826907, - 0.021497944, - 0.016138521, - 0.046133388, - 0.01523974, - 0.015660681, - 0.017292616, - 0.020530061, - 0.016093722, - 0.016341592, - 0.046256749, - 0.015779173, - 0.015746837, - 0.015611975, - 0.016996482, - 0.021577572, - 0.016406715, - 0.015906409, - 0.015832185, - 0.047790678, - 0.015803975, - 0.015824113, - 0.01590215, - 0.016162937, - 0.020576014, - 0.016621113, - 0.015987491, - 0.016135071, - 0.015875201, - 0.015948024, - 0.01573033, - 0.015933253, - 0.016090119, - 0.015618277, - 0.016851979, - 0.016172898, - 0.015540249, - 0.015570229, - 0.021071741, - 0.01572953 - ], - [ - 0.019621863, - 0.015919892, - 0.016440668, - 0.050280074, - 0.021711794, - 0.016093709, - 0.01724701, - 0.035826263, - 0.015851675, - 0.015913959, - 0.016038233, - 0.046758066, - 0.02070723, - 0.01574927, - 0.016246158, - 0.017122535, - 0.023233503, - 0.015860918, - 0.01596954, - 0.016019641, - 0.015924273, - 0.021923375, - 0.016140562, - 0.015742958, - 0.015724884, - 0.015605384, - 0.015393075, - 0.015979804, - 0.015999877, - 0.015615426, - 0.02309493, - 0.015699285, - 0.016015774, - 0.015666012, - 0.015603293, - 0.040047375, - 0.015951989, - 0.016035861, - 0.016161315, - 0.016155446 - ], - [ - 0.020121387, - 0.016181212, - 0.015955852, - 0.044898494, - 0.021693182, - 0.018934402, - 0.017377916, - 0.037992385, - 0.016095523, - 0.015798176, - 0.015810421, - 0.04724581, - 0.021034915, - 0.015818319, - 0.01575796, - 0.017352917, - 0.023365077, - 0.015735665, - 0.015861822, - 0.015877459, - 0.015976077, - 0.022347404, - 0.015880306, - 0.015829057, - 0.015863335, - 0.015665955, - 0.015656946, - 0.015884199, - 0.015996495, - 0.015776377, - 0.0158899, - 0.015765194, - 0.016394123, - 0.015749898, - 0.015928707, - 0.031877486, - 0.015623018, - 0.0160642, - 0.016818973, - 0.015810005 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 1.1825934999999999E-4, - "scoreError" : 3.7452934349419985E-6, - "scoreConfidence" : [ - 1.14514056565058E-4, - 1.2200464343494198E-4 - ], - "scorePercentiles" : { - "0.0" : 1.10757E-4, - "50.0" : 1.15564E-4, - "90.0" : 1.2200210000000001E-4, - "95.0" : 1.3085164999999998E-4, - "99.0" : 2.1537974000000054E-4, - "99.9" : 3.01335E-4, - "99.99" : 3.01335E-4, - "99.999" : 3.01335E-4, - "99.9999" : 3.01335E-4, - "100.0" : 3.01335E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.36964E-4, - 1.26697E-4, - 1.15107E-4, - 1.14946E-4, - 1.16366E-4, - 1.14794E-4, - 1.16833E-4, - 1.14383E-4, - 1.14531E-4, - 1.20509E-4, - 1.26424E-4, - 1.1475E-4, - 1.15719E-4, - 1.14585E-4, - 1.20153E-4, - 1.16874E-4, - 1.13118E-4, - 1.16313E-4, - 1.18648E-4, - 1.17302E-4, - 1.13351E-4, - 1.11902E-4, - 1.13929E-4, - 1.13684E-4, - 1.17018E-4, - 1.1675E-4, - 1.15551E-4, - 1.16091E-4, - 1.49809E-4, - 1.16544E-4, - 1.1477E-4, - 1.16945E-4, - 1.18235E-4, - 1.17906E-4, - 1.33124E-4, - 1.14792E-4, - 1.21436E-4, - 1.19919E-4, - 1.18827E-4, - 1.16132E-4 - ], - [ - 1.29607E-4, - 1.27428E-4, - 1.14795E-4, - 1.18903E-4, - 1.12432E-4, - 1.11876E-4, - 1.14024E-4, - 1.15359E-4, - 1.14047E-4, - 1.12329E-4, - 1.17899E-4, - 1.12481E-4, - 1.20407E-4, - 1.13077E-4, - 1.13567E-4, - 1.11775E-4, - 1.11973E-4, - 1.12384E-4, - 1.16404E-4, - 1.18577E-4, - 1.15127E-4, - 1.16076E-4, - 1.12325E-4, - 1.14275E-4, - 1.12722E-4, - 1.16041E-4, - 1.15111E-4, - 1.13473E-4, - 1.19296E-4, - 1.16163E-4, - 1.15791E-4, - 1.18604E-4, - 1.16591E-4, - 1.16494E-4, - 1.14155E-4, - 1.16668E-4, - 1.14783E-4, - 1.18831E-4, - 1.15489E-4, - 1.18063E-4 - ], - [ - 1.28309E-4, - 1.29629E-4, - 1.14028E-4, - 1.12589E-4, - 1.12226E-4, - 1.15188E-4, - 1.18387E-4, - 1.13963E-4, - 1.14469E-4, - 1.17799E-4, - 1.12801E-4, - 1.12522E-4, - 1.12839E-4, - 1.14175E-4, - 1.13417E-4, - 1.12044E-4, - 1.18469E-4, - 1.1352E-4, - 1.12725E-4, - 1.18124E-4, - 1.13595E-4, - 1.13012E-4, - 1.13554E-4, - 1.17061E-4, - 1.15698E-4, - 1.16508E-4, - 1.15692E-4, - 1.16079E-4, - 1.19341E-4, - 1.19633E-4, - 1.15259E-4, - 1.13187E-4, - 1.13965E-4, - 1.12648E-4, - 1.15788E-4, - 1.15555E-4, - 1.13279E-4, - 1.17242E-4, - 1.12917E-4, - 1.13022E-4 - ], - [ - 1.30916E-4, - 3.01335E-4, - 1.16154E-4, - 1.12174E-4, - 1.15315E-4, - 1.15614E-4, - 1.14078E-4, - 1.15513E-4, - 1.15159E-4, - 1.13578E-4, - 1.13324E-4, - 1.17424E-4, - 1.1667E-4, - 1.15606E-4, - 1.17348E-4, - 1.15225E-4, - 1.18489E-4, - 1.14995E-4, - 1.15115E-4, - 1.17737E-4, - 1.15735E-4, - 1.12234E-4, - 1.1462E-4, - 1.13209E-4, - 1.14801E-4, - 1.15672E-4, - 1.55954E-4, - 1.3577E-4, - 1.14255E-4, - 1.14953E-4, - 1.18041E-4, - 1.16545E-4, - 1.14604E-4, - 1.15989E-4, - 1.13974E-4, - 1.15819E-4, - 1.23264E-4, - 1.16361E-4, - 1.15573E-4, - 1.14532E-4 - ], - [ - 1.34417E-4, - 1.25648E-4, - 1.13885E-4, - 1.17493E-4, - 1.13297E-4, - 1.13923E-4, - 1.22065E-4, - 1.14658E-4, - 1.14182E-4, - 1.12674E-4, - 1.12491E-4, - 1.1356E-4, - 1.12108E-4, - 1.13473E-4, - 1.15752E-4, - 1.10757E-4, - 1.15794E-4, - 1.1475E-4, - 1.14784E-4, - 1.17411E-4, - 1.1517E-4, - 1.1291E-4, - 1.14485E-4, - 1.17241E-4, - 1.16008E-4, - 1.18616E-4, - 2.1598E-4, - 1.12714E-4, - 1.32118E-4, - 1.13298E-4, - 1.14352E-4, - 1.20645E-4, - 1.17162E-4, - 1.1782E-4, - 1.16358E-4, - 1.16146E-4, - 1.15816E-4, - 1.23821E-4, - 1.18284E-4, - 1.18719E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.5134146500000016E-4, - "scoreError" : 1.6435579926037524E-5, - "scoreConfidence" : [ - 1.3490588507396263E-4, - 1.677770449260377E-4 - ], - "scorePercentiles" : { - "0.0" : 1.04726E-4, - "50.0" : 1.14947E-4, - "90.0" : 1.869011E-4, - "95.0" : 3.780382999999986E-4, - "99.0" : 4.2063475E-4, - "99.9" : 4.22929E-4, - "99.99" : 4.22929E-4, - "99.999" : 4.22929E-4, - "99.9999" : 4.22929E-4, - "100.0" : 4.22929E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 4.13967E-4, - 4.13698E-4, - 1.77167E-4, - 1.76215E-4, - 1.67389E-4, - 1.66302E-4, - 1.6835E-4, - 1.66028E-4, - 1.65342E-4, - 1.67569E-4, - 1.75149E-4, - 1.7219E-4, - 1.91097E-4, - 1.72024E-4, - 1.76005E-4, - 1.75809E-4, - 2.23988E-4, - 1.12063E-4, - 1.07176E-4, - 1.0732E-4, - 1.05318E-4, - 1.04887E-4, - 1.12351E-4, - 1.07378E-4, - 1.04956E-4, - 1.05532E-4, - 1.06885E-4, - 1.0545E-4, - 1.0754E-4, - 1.0572E-4, - 1.05747E-4, - 1.96382E-4, - 1.06411E-4, - 1.06938E-4, - 1.05E-4, - 1.04726E-4, - 1.06423E-4, - 1.05662E-4, - 1.07471E-4, - 1.05601E-4 - ], - [ - 4.08296E-4, - 4.14096E-4, - 1.78064E-4, - 1.72946E-4, - 1.76758E-4, - 1.6982E-4, - 1.73014E-4, - 1.66753E-4, - 1.73412E-4, - 1.72356E-4, - 1.75243E-4, - 1.72988E-4, - 1.7975E-4, - 1.77665E-4, - 1.76129E-4, - 1.76594E-4, - 2.25694E-4, - 1.1176E-4, - 1.08584E-4, - 1.08423E-4, - 1.08738E-4, - 1.05892E-4, - 1.05659E-4, - 1.06013E-4, - 1.05094E-4, - 1.0728E-4, - 1.05556E-4, - 1.05618E-4, - 1.05523E-4, - 1.05314E-4, - 1.05731E-4, - 1.05458E-4, - 1.06917E-4, - 1.05803E-4, - 1.05817E-4, - 1.06298E-4, - 1.0766E-4, - 1.10631E-4, - 1.06801E-4, - 1.06269E-4 - ], - [ - 4.2069E-4, - 4.10465E-4, - 1.79735E-4, - 1.74425E-4, - 1.73011E-4, - 1.68878E-4, - 1.68672E-4, - 1.6819E-4, - 1.68743E-4, - 1.66773E-4, - 1.77614E-4, - 1.79728E-4, - 1.86749E-4, - 1.732E-4, - 1.97363E-4, - 1.78578E-4, - 2.36807E-4, - 1.12527E-4, - 1.07354E-4, - 1.07592E-4, - 1.07189E-4, - 1.10403E-4, - 1.0499E-4, - 1.05679E-4, - 1.04946E-4, - 1.05131E-4, - 1.06265E-4, - 1.05279E-4, - 1.05178E-4, - 1.05384E-4, - 1.0662E-4, - 1.45345E-4, - 1.0615E-4, - 1.05693E-4, - 1.06253E-4, - 1.07317E-4, - 1.06977E-4, - 1.05911E-4, - 1.0939E-4, - 1.06713E-4 - ], - [ - 4.15165E-4, - 4.22929E-4, - 1.78008E-4, - 1.74847E-4, - 1.72696E-4, - 1.71024E-4, - 1.76709E-4, - 1.73445E-4, - 1.77065E-4, - 1.78445E-4, - 1.77974E-4, - 1.77119E-4, - 1.75281E-4, - 1.74882E-4, - 1.76603E-4, - 1.69674E-4, - 2.34166E-4, - 1.11425E-4, - 1.06844E-4, - 1.08257E-4, - 1.0539E-4, - 1.05462E-4, - 1.06082E-4, - 1.0627E-4, - 1.05892E-4, - 1.06212E-4, - 1.05924E-4, - 1.05924E-4, - 1.07109E-4, - 1.05422E-4, - 1.05866E-4, - 1.48209E-4, - 1.06762E-4, - 1.05157E-4, - 1.05337E-4, - 1.04838E-4, - 1.05424E-4, - 1.06436E-4, - 1.05889E-4, - 1.06622E-4 - ], - [ - 4.00278E-4, - 3.84252E-4, - 1.86918E-4, - 1.7957E-4, - 1.86163E-4, - 1.82831E-4, - 1.78159E-4, - 1.77871E-4, - 1.78445E-4, - 1.79782E-4, - 1.89607E-4, - 1.85787E-4, - 1.81017E-4, - 1.83881E-4, - 1.84659E-4, - 1.80629E-4, - 2.59978E-4, - 1.19643E-4, - 1.16418E-4, - 1.37143E-4, - 1.15646E-4, - 1.14332E-4, - 1.14904E-4, - 1.15154E-4, - 1.15015E-4, - 1.14518E-4, - 1.13656E-4, - 1.14576E-4, - 1.14663E-4, - 1.14469E-4, - 1.15284E-4, - 1.1499E-4, - 1.15045E-4, - 1.14572E-4, - 1.13848E-4, - 1.13216E-4, - 1.15034E-4, - 1.14685E-4, - 1.18894E-4, - 1.18426E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0024601392450000004, - "scoreError" : 0.0010548092536902507, - "scoreConfidence" : [ - 0.0014053299913097496, - 0.003514948498690251 - ], - "scorePercentiles" : { - "0.0" : 0.001031204, - "50.0" : 0.0010644295000000002, - "90.0" : 0.0017554603, - "95.0" : 0.01783406405, - "99.0" : 0.018756401080000006, - "99.9" : 0.019435475, - "99.99" : 0.019435475, - "99.999" : 0.019435475, - "99.9999" : 0.019435475, - "100.0" : 0.019435475 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001072861, - 0.001078154, - 0.001102116, - 0.001737676, - 0.001748209, - 0.017896372, - 0.001063717, - 0.001061816, - 0.001060712, - 0.001063329, - 0.00105633, - 0.017834479, - 0.001035089, - 0.001034462, - 0.001038337, - 0.001034966, - 0.001039787, - 0.001040573, - 0.001714653, - 0.001746362, - 0.001734356, - 0.001714518, - 0.001699058, - 0.017861109, - 0.00103431, - 0.00103621, - 0.001039608, - 0.001036034, - 0.001039599, - 0.001031301, - 0.001040688, - 0.00112505, - 0.001203795, - 0.001039759, - 0.001074845, - 0.001035093, - 0.001041456, - 0.00103659, - 0.001250803, - 0.001210056 - ], - [ - 0.001064721, - 0.001078123, - 0.001112574, - 0.001724965, - 0.001756266, - 0.017962556, - 0.001061451, - 0.001063299, - 0.001062569, - 0.00106058, - 0.001055, - 0.017745105, - 0.001062002, - 0.001061004, - 0.001058914, - 0.001058813, - 0.001070598, - 0.00106206, - 0.001706192, - 0.001738778, - 0.00173548, - 0.001725894, - 0.00172879, - 0.01806904, - 0.00106191, - 0.001065488, - 0.001064487, - 0.001065245, - 0.001064361, - 0.001063011, - 0.001058151, - 0.001064581, - 0.001064548, - 0.001042095, - 0.001068396, - 0.001033948, - 0.001039619, - 0.001036321, - 0.001038144, - 0.001036995 - ], - [ - 0.001040736, - 0.001203414, - 0.001078115, - 0.001667255, - 0.001737603, - 0.01782618, - 0.001060841, - 0.001060625, - 0.001057795, - 0.001060147, - 0.001058504, - 0.017746356, - 0.001064521, - 0.001060336, - 0.001057498, - 0.00107789, - 0.001076477, - 0.001084607, - 0.001717115, - 0.001733872, - 0.001732883, - 0.001761166, - 0.002107207, - 0.019435475, - 0.001059113, - 0.001260692, - 0.001248574, - 0.00124398, - 0.001147893, - 0.001057169, - 0.001062513, - 0.001065647, - 0.00110032, - 0.001156575, - 0.001213692, - 0.001061069, - 0.001069345, - 0.001061417, - 0.001061963, - 0.001064388 - ], - [ - 0.001040893, - 0.001041342, - 0.001078708, - 0.0016595, - 0.001710196, - 0.018113621, - 0.001034693, - 0.001035923, - 0.00103999, - 0.001037507, - 0.001036075, - 0.017693007, - 0.001063687, - 0.001061428, - 0.001067295, - 0.001060865, - 0.001067075, - 0.001063779, - 0.001695695, - 0.001773727, - 0.001714052, - 0.001727551, - 0.001738919, - 0.018437728, - 0.001037539, - 0.0010409, - 0.001051733, - 0.001038868, - 0.001040719, - 0.001047051, - 0.001040525, - 0.001262258, - 0.00103945, - 0.001037713, - 0.001070787, - 0.00103948, - 0.001042968, - 0.001062222, - 0.001066581, - 0.001063244 - ], - [ - 0.001040035, - 0.001078096, - 0.001080195, - 0.001670866, - 0.001699854, - 0.017967355, - 0.001033334, - 0.001035129, - 0.001031445, - 0.001037198, - 0.001031204, - 0.017751549, - 0.00104476, - 0.001032935, - 0.00103648, - 0.001034922, - 0.001039896, - 0.001037799, - 0.001656975, - 0.001692586, - 0.001728575, - 0.001841332, - 0.001742335, - 0.01875962, - 0.001057969, - 0.001065187, - 0.001067789, - 0.001074635, - 0.001065806, - 0.00107072, - 0.001062706, - 0.001063995, - 0.00106211, - 0.001064471, - 0.001104204, - 0.001084798, - 0.001043676, - 0.001109279, - 0.001034171, - 0.001039284 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.017118883294999995, - "scoreError" : 0.006629950539653628, - "scoreConfidence" : [ - 0.010488932755346366, - 0.02374883383465362 - ], - "scorePercentiles" : { - "0.0" : 0.010169741, - "50.0" : 0.0106741645, - "90.0" : 0.011109742, - "95.0" : 0.12600573709999868, - "99.0" : 0.14272167963, - "99.9" : 0.146324271, - "99.99" : 0.146324271, - "99.999" : 0.146324271, - "99.9999" : 0.146324271, - "100.0" : 0.146324271 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.010860657, - 0.141912459, - 0.010502557, - 0.010257646, - 0.010531558, - 0.010725375, - 0.010851223, - 0.010974195, - 0.010766343, - 0.010912489, - 0.141483319, - 0.010566327, - 0.01082226, - 0.010504381, - 0.010713519, - 0.010992787, - 0.011080375, - 0.010434018, - 0.010904795, - 0.010749555, - 0.010613462, - 0.133977192, - 0.011299381, - 0.010880943, - 0.010403146, - 0.010518319, - 0.010169741, - 0.011442237, - 0.010566656, - 0.010320025, - 0.010649807, - 0.010431594, - 0.010631924, - 0.010587802, - 0.010289876, - 0.010805241, - 0.010300966, - 0.011965285, - 0.010339106, - 0.010384316 - ], - [ - 0.011112766, - 0.011421263, - 0.010713608, - 0.011060613, - 0.010686825, - 0.010532701, - 0.010902187, - 0.010885258, - 0.010547931, - 0.010480179, - 0.010634922, - 0.010660365, - 0.010404303, - 0.010668593, - 0.010615362, - 0.010599695, - 0.010802789, - 0.010984443, - 0.010630458, - 0.010600906, - 0.010560614, - 0.010588959, - 0.010338695, - 0.010602888, - 0.010621062, - 0.010599502, - 0.010722882, - 0.01045618, - 0.010669671, - 0.010486405, - 0.010803767, - 0.131935026, - 0.010629166, - 0.010627758, - 0.010580396, - 0.010514398, - 0.010649863, - 0.010624128, - 0.010716672, - 0.010590243 - ], - [ - 0.010984691, - 0.142727264, - 0.011337156, - 0.011317687, - 0.010439877, - 0.010646833, - 0.010980504, - 0.010740781, - 0.010539889, - 0.010728374, - 0.142168827, - 0.010769838, - 0.010451219, - 0.013349248, - 0.011282461, - 0.010829311, - 0.010724094, - 0.010528761, - 0.010589168, - 0.010676708, - 0.010663738, - 0.134666133, - 0.010756881, - 0.010453349, - 0.010436474, - 0.010715887, - 0.010322129, - 0.010730989, - 0.010553881, - 0.011148916, - 0.010976642, - 0.010580572, - 0.010783126, - 0.010420527, - 0.010782135, - 0.010478048, - 0.010572517, - 0.010620726, - 0.010623551, - 0.011082526 - ], - [ - 0.010886405, - 0.010573641, - 0.011020508, - 0.010416943, - 0.010680921, - 0.010689526, - 0.01087156, - 0.010677344, - 0.0107125, - 0.010757008, - 0.01085479, - 0.010617031, - 0.010456257, - 0.010698293, - 0.010671883, - 0.010699871, - 0.010684861, - 0.010739043, - 0.010793895, - 0.010687273, - 0.010727872, - 0.010775868, - 0.010771738, - 0.010753789, - 0.010478884, - 0.010479863, - 0.010632363, - 0.010685959, - 0.010785581, - 0.010539363, - 0.010773312, - 0.010568506, - 0.010756559, - 0.010694645, - 0.010747223, - 0.010685147, - 0.010302887, - 0.01088228, - 0.010742906, - 0.010852103 - ], - [ - 0.010912664, - 0.146324271, - 0.01048435, - 0.010504689, - 0.010580496, - 0.010409538, - 0.010954114, - 0.010676446, - 0.010645088, - 0.010666726, - 0.141123486, - 0.010718236, - 0.010473838, - 0.010408836, - 0.01058274, - 0.010418044, - 0.010475693, - 0.010616968, - 0.010596095, - 0.010900569, - 0.010548382, - 0.010535948, - 0.010724393, - 0.010954027, - 0.010612178, - 0.010632689, - 0.010578366, - 0.010710501, - 0.010491071, - 0.010656214, - 0.134534859, - 0.010717414, - 0.010556927, - 0.010652965, - 0.010722263, - 0.010622508, - 0.010715477, - 0.010627779, - 0.010689773, - 0.0106259 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 8.731592999999996E-5, - "scoreError" : 2.3834368103813865E-5, - "scoreConfidence" : [ - 6.34815618961861E-5, - 1.1115029810381381E-4 - ], - "scorePercentiles" : { - "0.0" : 1.4574E-5, - "50.0" : 5.2226E-5, - "90.0" : 2.796342E-4, - "95.0" : 2.8341735E-4, - "99.0" : 2.8811742E-4, - "99.9" : 3.25378E-4, - "99.99" : 3.25378E-4, - "99.999" : 3.25378E-4, - "99.9999" : 3.25378E-4, - "100.0" : 3.25378E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 2.77688E-4, - 2.78827E-4, - 2.78863E-4, - 2.78786E-4, - 3.25378E-4, - 2.81848E-4, - 2.80963E-4, - 2.83472E-4, - 6.0661E-5, - 5.2696E-5, - 5.3328E-5, - 5.2689E-5, - 5.3083E-5, - 5.2056E-5, - 5.224E-5, - 7.1291E-5, - 5.2139E-5, - 5.4031E-5, - 5.3482E-5, - 5.1565E-5, - 1.13785E-4, - 5.1665E-5, - 1.01858E-4, - 1.6402E-5, - 1.5416E-5, - 1.6329E-5, - 1.5892E-5, - 1.5219E-5, - 1.518E-5, - 1.7209E-5, - 1.7002E-5, - 1.6679E-5, - 1.603E-5, - 1.6463E-5, - 1.5536E-5, - 1.6285E-5, - 1.7311E-5, - 1.6121E-5, - 1.6539E-5, - 1.5676E-5 - ], - [ - 2.79816E-4, - 2.79438E-4, - 2.7829E-4, - 2.77896E-4, - 2.7762E-4, - 2.80893E-4, - 2.77418E-4, - 2.80288E-4, - 6.1375E-5, - 5.3186E-5, - 5.2544E-5, - 5.2545E-5, - 5.2212E-5, - 5.2048E-5, - 5.1882E-5, - 6.8635E-5, - 5.2166E-5, - 5.3288E-5, - 5.2785E-5, - 5.0999E-5, - 1.28471E-4, - 5.5035E-5, - 1.08102E-4, - 1.5192E-5, - 1.5274E-5, - 1.4574E-5, - 1.479E-5, - 2.2274E-5, - 1.6371E-5, - 1.5619E-5, - 1.6318E-5, - 1.652E-5, - 1.6454E-5, - 1.5176E-5, - 1.5908E-5, - 1.5429E-5, - 1.5263E-5, - 1.58E-5, - 1.5444E-5, - 1.7078E-5 - ], - [ - 2.79636E-4, - 2.78531E-4, - 2.78275E-4, - 2.78612E-4, - 2.7674E-4, - 2.79618E-4, - 2.78933E-4, - 2.8128E-4, - 6.1924E-5, - 5.3998E-5, - 5.3112E-5, - 5.3334E-5, - 5.3751E-5, - 5.2295E-5, - 5.2321E-5, - 7.9297E-5, - 5.2381E-5, - 5.3596E-5, - 5.423E-5, - 5.2822E-5, - 1.51936E-4, - 5.1612E-5, - 1.0802E-4, - 1.6682E-5, - 1.5844E-5, - 1.5964E-5, - 1.5836E-5, - 1.6407E-5, - 1.6162E-5, - 1.5492E-5, - 1.75E-5, - 1.7111E-5, - 1.6868E-5, - 1.5091E-5, - 1.5629E-5, - 1.5785E-5, - 1.6261E-5, - 1.5867E-5, - 1.579E-5, - 1.6243E-5 - ], - [ - 2.83724E-4, - 2.85326E-4, - 2.86149E-4, - 2.87169E-4, - 2.83908E-4, - 2.84502E-4, - 2.88127E-4, - 2.78976E-4, - 6.2257E-5, - 5.398E-5, - 5.4325E-5, - 5.351E-5, - 5.3912E-5, - 5.2788E-5, - 5.2401E-5, - 6.8422E-5, - 5.4978E-5, - 5.6272E-5, - 5.5747E-5, - 5.1639E-5, - 1.09669E-4, - 5.2054E-5, - 1.03544E-4, - 3.0068E-5, - 1.5081E-5, - 1.4625E-5, - 1.5784E-5, - 1.5558E-5, - 1.5978E-5, - 1.5984E-5, - 1.676E-5, - 1.6777E-5, - 1.6515E-5, - 1.6244E-5, - 1.4964E-5, - 1.478E-5, - 1.6648E-5, - 1.5502E-5, - 1.6308E-5, - 1.614E-5 - ], - [ - 2.79102E-4, - 2.82379E-4, - 2.78219E-4, - 2.80935E-4, - 2.7831E-4, - 2.80929E-4, - 2.79318E-4, - 2.87048E-4, - 6.069E-5, - 5.3664E-5, - 5.2391E-5, - 5.1984E-5, - 5.2958E-5, - 5.3454E-5, - 5.3269E-5, - 8.9247E-5, - 5.2804E-5, - 5.3342E-5, - 5.3965E-5, - 5.103E-5, - 1.66377E-4, - 5.0932E-5, - 9.9688E-5, - 1.5196E-5, - 1.6341E-5, - 2.2791E-5, - 1.6292E-5, - 1.6136E-5, - 1.6054E-5, - 1.5848E-5, - 1.6118E-5, - 1.5988E-5, - 1.6336E-5, - 1.8567E-5, - 1.7023E-5, - 1.6038E-5, - 1.6572E-5, - 1.6706E-5, - 1.8722E-5, - 2.4443E-5 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 1.9222423500000004E-4, - "scoreError" : 1.1269304230169972E-5, - "scoreConfidence" : [ - 1.8095493076983007E-4, - 2.0349353923017002E-4 - ], - "scorePercentiles" : { - "0.0" : 1.37196E-4, - "50.0" : 1.72587E-4, - "90.0" : 2.270692E-4, - "95.0" : 2.5148379999999983E-4, - "99.0" : 4.187417000000002E-4, - "99.9" : 4.75658E-4, - "99.99" : 4.75658E-4, - "99.999" : 4.75658E-4, - "99.9999" : 4.75658E-4, - "100.0" : 4.75658E-4 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.43981E-4, - 1.49457E-4, - 1.38904E-4, - 1.38064E-4, - 1.42417E-4, - 1.40324E-4, - 3.76927E-4, - 2.23079E-4, - 2.52373E-4, - 2.2541E-4, - 2.23503E-4, - 1.67608E-4, - 1.6747E-4, - 2.2307E-4, - 1.68567E-4, - 1.70957E-4, - 1.72351E-4, - 1.7493E-4, - 1.67616E-4, - 1.73249E-4, - 1.72516E-4, - 2.26972E-4, - 2.23448E-4, - 2.73344E-4, - 2.26614E-4, - 2.24388E-4, - 2.30979E-4, - 2.26253E-4, - 1.71085E-4, - 2.25695E-4, - 1.77258E-4, - 1.74905E-4, - 1.75891E-4, - 1.71652E-4, - 2.2439E-4, - 1.68453E-4, - 1.66989E-4, - 1.68315E-4, - 1.65479E-4, - 1.6739E-4 - ], - [ - 1.41084E-4, - 1.44576E-4, - 2.03956E-4, - 1.37196E-4, - 1.4599E-4, - 1.38296E-4, - 4.18959E-4, - 1.67724E-4, - 1.75026E-4, - 2.31239E-4, - 2.25368E-4, - 1.67567E-4, - 1.68924E-4, - 1.63294E-4, - 2.27937E-4, - 2.24367E-4, - 1.73908E-4, - 1.72658E-4, - 1.66157E-4, - 1.68913E-4, - 1.66617E-4, - 2.26161E-4, - 1.66085E-4, - 2.80524E-4, - 2.25238E-4, - 2.24203E-4, - 2.30358E-4, - 2.27365E-4, - 1.74042E-4, - 2.24825E-4, - 1.71335E-4, - 2.23549E-4, - 1.71536E-4, - 1.65203E-4, - 2.24472E-4, - 2.22765E-4, - 2.23681E-4, - 1.70495E-4, - 2.26878E-4, - 2.24439E-4 - ], - [ - 2.06189E-4, - 2.04529E-4, - 1.37392E-4, - 1.47677E-4, - 1.46298E-4, - 1.39863E-4, - 3.86682E-4, - 1.66356E-4, - 1.75872E-4, - 2.31238E-4, - 2.22495E-4, - 2.23821E-4, - 1.75336E-4, - 1.72283E-4, - 1.70103E-4, - 1.63004E-4, - 1.73603E-4, - 1.81032E-4, - 1.6907E-4, - 1.71698E-4, - 1.65741E-4, - 2.23672E-4, - 1.67413E-4, - 2.77159E-4, - 2.27507E-4, - 1.6934E-4, - 1.7731E-4, - 1.71913E-4, - 1.69426E-4, - 1.66013E-4, - 2.22928E-4, - 2.28563E-4, - 1.71229E-4, - 2.22966E-4, - 2.23569E-4, - 1.67219E-4, - 1.66169E-4, - 2.24876E-4, - 2.23075E-4, - 1.68392E-4 - ], - [ - 2.05207E-4, - 2.03422E-4, - 1.38569E-4, - 1.40615E-4, - 2.11216E-4, - 2.0529E-4, - 4.75658E-4, - 1.65938E-4, - 1.67444E-4, - 1.71123E-4, - 2.24193E-4, - 1.64574E-4, - 1.63432E-4, - 1.6833E-4, - 1.69436E-4, - 2.23132E-4, - 1.83426E-4, - 1.7523E-4, - 1.67638E-4, - 1.73687E-4, - 2.23402E-4, - 1.65482E-4, - 2.23983E-4, - 2.77243E-4, - 1.74489E-4, - 2.24182E-4, - 1.79363E-4, - 1.74012E-4, - 1.67374E-4, - 1.70092E-4, - 1.71926E-4, - 2.24791E-4, - 1.73009E-4, - 1.65989E-4, - 2.26765E-4, - 2.24802E-4, - 1.69172E-4, - 1.65178E-4, - 1.71342E-4, - 1.68098E-4 - ], - [ - 1.4463E-4, - 1.42977E-4, - 1.38518E-4, - 1.41592E-4, - 1.43744E-4, - 1.37649E-4, - 3.97229E-4, - 1.64139E-4, - 2.2708E-4, - 2.25311E-4, - 1.68513E-4, - 1.67379E-4, - 1.69931E-4, - 2.24226E-4, - 2.26018E-4, - 1.64994E-4, - 1.78499E-4, - 1.75942E-4, - 1.67267E-4, - 1.65643E-4, - 1.66916E-4, - 1.66992E-4, - 1.65757E-4, - 2.34589E-4, - 1.72112E-4, - 1.68365E-4, - 1.8901E-4, - 1.78807E-4, - 1.78427E-4, - 2.26194E-4, - 2.24414E-4, - 2.25074E-4, - 1.73803E-4, - 2.26365E-4, - 1.66931E-4, - 1.66072E-4, - 1.68169E-4, - 1.66422E-4, - 1.69193E-4, - 1.67496E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.0024204378449999998, - "scoreError" : 3.302155193117049E-4, - "scoreConfidence" : [ - 0.002090222325688295, - 0.0027506533643117045 - ], - "scorePercentiles" : { - "0.0" : 0.001397437, - "50.0" : 0.0018557550000000002, - "90.0" : 0.003990120000000002, - "95.0" : 0.0057593140999999985, - "99.0" : 0.00774959012, - "99.9" : 0.007758316, - "99.99" : 0.007758316, - "99.999" : 0.007758316, - "99.9999" : 0.007758316, - "100.0" : 0.007758316 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001745664, - 0.0027131, - 0.001411746, - 0.002309932, - 0.003657741, - 0.002384034, - 0.002465791, - 0.002482488, - 0.001781463, - 0.001952838, - 0.004638187, - 0.001953914, - 0.00184541, - 0.001780518, - 0.001739404, - 0.002545777, - 0.00540997, - 0.002397603, - 0.002514014, - 0.001719634, - 0.001719102, - 0.00161551, - 0.002128134, - 0.00211726, - 0.001642201, - 0.007519429, - 0.001806662, - 0.001880757, - 0.001836457, - 0.002544415, - 0.001715885, - 0.001719018, - 0.001815001, - 0.003153637, - 0.007551237, - 0.001824258, - 0.001909221, - 0.001839952, - 0.002612655, - 0.00246977 - ], - [ - 0.001442322, - 0.002011837, - 0.002033622, - 0.002039997, - 0.002907797, - 0.002316592, - 0.001445979, - 0.00205532, - 0.001516328, - 0.001975158, - 0.003105472, - 0.002041894, - 0.001414324, - 0.001401971, - 0.001403063, - 0.001399951, - 0.007733267, - 0.001949463, - 0.002731938, - 0.001874987, - 0.001786053, - 0.002491656, - 0.001727823, - 0.001721071, - 0.001704466, - 0.005765185, - 0.001691181, - 0.001779876, - 0.002500895, - 0.001719725, - 0.001686103, - 0.001600202, - 0.001418156, - 0.002038438, - 0.007749755, - 0.001788134, - 0.001880717, - 0.001841581, - 0.001791688, - 0.001756385 - ], - [ - 0.001775601, - 0.002735682, - 0.001420411, - 0.002048675, - 0.004281168, - 0.001641772, - 0.001760078, - 0.002463345, - 0.002528191, - 0.002049271, - 0.003273035, - 0.001447208, - 0.001399506, - 0.0016476, - 0.001397437, - 0.001405071, - 0.005400093, - 0.002398656, - 0.001760074, - 0.001746726, - 0.00242473, - 0.001651081, - 0.002194262, - 0.001469919, - 0.002467302, - 0.007758316, - 0.002645916, - 0.00272366, - 0.001859802, - 0.002609815, - 0.001763405, - 0.001741617, - 0.002467746, - 0.001571618, - 0.005511538, - 0.001680717, - 0.001749767, - 0.002460556, - 0.001722213, - 0.001641792 - ], - [ - 0.001483534, - 0.001963648, - 0.001449759, - 0.001448889, - 0.004027051, - 0.002370715, - 0.002502064, - 0.002511575, - 0.002583883, - 0.002710064, - 0.004693267, - 0.001708671, - 0.001839147, - 0.00179692, - 0.001787236, - 0.001852523, - 0.007712446, - 0.002685462, - 0.002744269, - 0.001872445, - 0.001829839, - 0.001761559, - 0.002454401, - 0.001801923, - 0.002640974, - 0.007187758, - 0.001778286, - 0.002730209, - 0.001858987, - 0.001795227, - 0.001757146, - 0.001720565, - 0.001789837, - 0.002920429, - 0.005647767, - 0.00243928, - 0.001761841, - 0.001718811, - 0.001689592, - 0.00230008 - ], - [ - 0.001746625, - 0.002095294, - 0.002074834, - 0.002035362, - 0.003465275, - 0.001541023, - 0.00219736, - 0.001915782, - 0.00163959, - 0.002004697, - 0.004746331, - 0.002428073, - 0.001793293, - 0.001783592, - 0.001758206, - 0.001723515, - 0.007558363, - 0.002681097, - 0.002731805, - 0.001843867, - 0.001810651, - 0.001721939, - 0.001727855, - 0.001716284, - 0.001878291, - 0.005525686, - 0.001781841, - 0.001782354, - 0.001718423, - 0.001728554, - 0.002438074, - 0.001732313, - 0.00162812, - 0.00153538, - 0.007588053, - 0.001808885, - 0.00272606, - 0.001843202, - 0.001779432, - 0.001718576 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.CollectionBenchmark.drop", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.023899844045000007, - "scoreError" : 0.0013203635662903158, - "scoreConfidence" : [ - 0.022579480478709692, - 0.025220207611290322 - ], - "scorePercentiles" : { - "0.0" : 0.016214157, - "50.0" : 0.022965256500000003, - "90.0" : 0.0310706738, - "95.0" : 0.0339531378, - "99.0" : 0.0425152086, - "99.9" : 0.049356898, - "99.99" : 0.049356898, - "99.999" : 0.049356898, - "99.9999" : 0.049356898, - "100.0" : 0.049356898 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.049356898, - 0.030399854, - 0.034517446, - 0.021744687, - 0.018066976, - 0.029130475, - 0.019803874, - 0.021327273, - 0.031345529, - 0.032635802, - 0.016936038, - 0.022622295, - 0.025586448, - 0.018722934, - 0.019454503, - 0.025086184, - 0.017138199, - 0.023197128, - 0.026103439, - 0.019952901, - 0.019345258, - 0.025343693, - 0.016905899, - 0.022989648, - 0.020662292, - 0.022940865, - 0.019336007, - 0.026895438, - 0.017501235, - 0.027419478, - 0.027383953, - 0.020018598, - 0.020229185, - 0.028040608, - 0.021246802, - 0.016963589, - 0.020635436, - 0.023555534, - 0.021254746, - 0.019575384 - ], - [ - 0.033957788, - 0.029715953, - 0.033808759, - 0.026887503, - 0.017048241, - 0.027576523, - 0.020268363, - 0.023777886, - 0.030020789, - 0.032339754, - 0.017148399, - 0.020816815, - 0.027375078, - 0.023615661, - 0.030640877, - 0.029186006, - 0.017478529, - 0.017057488, - 0.021911176, - 0.02837971, - 0.02011902, - 0.019357808, - 0.026439817, - 0.017033769, - 0.024016054, - 0.019832973, - 0.019058614, - 0.019375611, - 0.025189386, - 0.018331978, - 0.023245872, - 0.019967352, - 0.019987714, - 0.018531887, - 0.025590493, - 0.01671666, - 0.024229138, - 0.01990028, - 0.01997619, - 0.019608635 - ], - [ - 0.025765932, - 0.03004115, - 0.042518237, - 0.025270103, - 0.024826801, - 0.029569068, - 0.019788824, - 0.028719742, - 0.031143327, - 0.036079048, - 0.017020053, - 0.022454849, - 0.020407092, - 0.022678646, - 0.036468211, - 0.028856589, - 0.017764019, - 0.01711552, - 0.022668652, - 0.028010959, - 0.025362179, - 0.019521522, - 0.026955843, - 0.021572288, - 0.023731686, - 0.019691939, - 0.022475016, - 0.023336853, - 0.031753788, - 0.017345668, - 0.024223184, - 0.026712267, - 0.019772538, - 0.023206062, - 0.026758331, - 0.017142335, - 0.022674179, - 0.02129695, - 0.022106822, - 0.019703535 - ], - [ - 0.027136397, - 0.0308429, - 0.042215397, - 0.025718259, - 0.0170407, - 0.027994298, - 0.020652098, - 0.02362418, - 0.031076999, - 0.028677479, - 0.017061917, - 0.020309429, - 0.027140003, - 0.022431174, - 0.030601242, - 0.036360054, - 0.017567896, - 0.016819837, - 0.021995351, - 0.025663596, - 0.021416039, - 0.018721816, - 0.023958168, - 0.016961319, - 0.023781328, - 0.020752712, - 0.022443531, - 0.023310813, - 0.030955777, - 0.024597566, - 0.024557114, - 0.028941767, - 0.023827487, - 0.01985028, - 0.026046325, - 0.017555459, - 0.035066724, - 0.029490333, - 0.02190043, - 0.019682997 - ], - [ - 0.024674474, - 0.031951488, - 0.033864784, - 0.026739056, - 0.017259538, - 0.023761075, - 0.024658144, - 0.029195269, - 0.031013747, - 0.038484694, - 0.017132464, - 0.016214157, - 0.029238148, - 0.023565681, - 0.030143608, - 0.018996242, - 0.02282188, - 0.018242949, - 0.031709839, - 0.02276625, - 0.021673594, - 0.019920493, - 0.025564011, - 0.016857949, - 0.023565184, - 0.019966135, - 0.019942526, - 0.018688435, - 0.027346612, - 0.017257977, - 0.023574967, - 0.022248581, - 0.019992454, - 0.023639304, - 0.02775663, - 0.018834853, - 0.020314446, - 0.020645658, - 0.025043855, - 0.02055158 - ] - ] - }, - "secondaryMetrics" : { - } - } -] - - diff --git a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.png b/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.png deleted file mode 100644 index cb15accdf11ecf886f1e0624d52f8c2a1f40d5f8..0000000000000000000000000000000000000000 Binary files a/previous-exams/2022-midterm-code/bench-results/CollectionBenchmarkResults_take.png and /dev/null differ diff --git a/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.json b/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.json deleted file mode 100644 index ef7225957ad5428b5faf73a3606ea594923140a9..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.json +++ /dev/null @@ -1,8292 +0,0 @@ -[ - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "true", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.0011861944200000003, - "scoreError" : 9.468556132050369E-5, - "scoreConfidence" : [ - 0.0010915088586794966, - 0.001280879981320504 - ], - "scorePercentiles" : { - "0.0" : 4.88139E-4, - "50.0" : 0.0012135190000000001, - "90.0" : 0.0014960688, - "95.0" : 0.00162990845, - "99.0" : 0.002288841670000003, - "99.9" : 0.004990054, - "99.99" : 0.004990054, - "99.999" : 0.004990054, - "99.9999" : 0.004990054, - "100.0" : 0.004990054 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001304058, - 0.001298496, - 0.001170409, - 0.001339631, - 0.001334817, - 0.001102557, - 0.001203327, - 0.001179525, - 0.001060429, - 0.001244345, - 0.001175425, - 0.001352902, - 0.001188718, - 0.001128695, - 0.001132496, - 0.001087717, - 0.00115625, - 0.001028496, - 0.001041221, - 0.001218259, - 0.001109968, - 0.001061908, - 0.001041795, - 7.43622E-4, - 6.89575E-4, - 6.58245E-4, - 8.17719E-4, - 6.90382E-4, - 6.45305E-4, - 6.77632E-4, - 7.13609E-4, - 7.73109E-4, - 9.04338E-4, - 7.54873E-4, - 7.97477E-4, - 8.66493E-4, - 7.18551E-4, - 9.25877E-4, - 7.64071E-4, - 7.7727E-4 - ], - [ - 0.001333458, - 0.001384272, - 0.001372758, - 0.00130676, - 0.001260775, - 0.001453995, - 0.001346011, - 0.001339505, - 0.001326671, - 0.001411627, - 0.001355902, - 0.001444786, - 0.001462232, - 0.001381247, - 0.001273545, - 0.001268675, - 0.001386344, - 0.00131742, - 0.001332703, - 0.001229275, - 0.001386584, - 0.001291317, - 0.001354057, - 0.001410679, - 0.001287115, - 0.001373863, - 0.001474732, - 0.00151112, - 0.001610941, - 0.001667496, - 0.001788101, - 0.001915084, - 0.001460344, - 0.00163047, - 0.001513617, - 0.001677678, - 0.001619239, - 0.001491891, - 0.00148663, - 0.001177567 - ], - [ - 0.001345933, - 0.001234396, - 0.001370726, - 0.001460069, - 0.001434697, - 0.001372518, - 0.001398059, - 0.001233615, - 0.001219739, - 0.001063007, - 9.19662E-4, - 9.76451E-4, - 8.20762E-4, - 0.001001987, - 8.44395E-4, - 6.98264E-4, - 7.6272E-4, - 7.62767E-4, - 6.938E-4, - 7.16296E-4, - 8.11477E-4, - 6.59355E-4, - 7.62291E-4, - 7.28177E-4, - 0.004990054, - 7.48552E-4, - 7.45999E-4, - 6.50658E-4, - 6.60054E-4, - 7.21663E-4, - 6.97747E-4, - 9.18411E-4, - 6.90393E-4, - 7.01726E-4, - 7.10807E-4, - 7.293E-4, - 8.75948E-4, - 7.4074E-4, - 7.51985E-4, - 7.31371E-4 - ], - [ - 0.001222681, - 0.00111247, - 0.001101088, - 0.001180677, - 0.001212401, - 0.001090922, - 0.00109057, - 0.001164763, - 0.001258862, - 0.001132345, - 0.001007507, - 0.001078679, - 0.001147936, - 0.001119162, - 0.001232988, - 0.001106727, - 0.001247159, - 0.00113776, - 0.001172976, - 0.00111549, - 0.001124179, - 0.001066768, - 0.00123246, - 0.001159606, - 0.001129301, - 0.001183873, - 0.001299745, - 0.001149341, - 0.001118714, - 0.001154781, - 0.002292617, - 0.001298778, - 0.001299525, - 0.001296932, - 0.001214637, - 0.001116941, - 0.001120779, - 0.001105576, - 0.00112325, - 0.001102039 - ], - [ - 0.0012402, - 0.001474788, - 0.001325545, - 0.001288007, - 0.00133604, - 0.001282142, - 0.001261273, - 0.00125784, - 0.001286769, - 0.00130464, - 0.001346377, - 0.001303073, - 0.001401975, - 0.001294309, - 0.001370502, - 0.001378595, - 0.00127251, - 0.001238024, - 0.001255577, - 0.001496533, - 0.001397694, - 0.001411788, - 0.001405834, - 0.001321425, - 0.001554417, - 8.80308E-4, - 7.45786E-4, - 0.001047125, - 0.001150237, - 0.001763902, - 0.001843808, - 0.001574874, - 0.001669, - 0.001559272, - 0.001564792, - 0.001490579, - 0.00158391, - 9.68588E-4, - 5.27033E-4, - 4.88139E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "true", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.005628886064999998, - "scoreError" : 5.960812965863038E-4, - "scoreConfidence" : [ - 0.005032804768413694, - 0.006224967361586302 - ], - "scorePercentiles" : { - "0.0" : 0.001324493, - "50.0" : 0.0051279375, - "90.0" : 0.0093012405, - "95.0" : 0.010389465599999995, - "99.0" : 0.01284107455, - "99.9" : 0.013696353, - "99.99" : 0.013696353, - "99.999" : 0.013696353, - "99.9999" : 0.013696353, - "100.0" : 0.013696353 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.012023208, - 0.00925602, - 0.009097269, - 0.009208218, - 0.009345478, - 0.009178583, - 0.010047344, - 0.006259496, - 0.006868334, - 0.003542142, - 0.004263114, - 0.004204459, - 0.004596538, - 0.004850382, - 0.003313024, - 0.003655041, - 0.007068476, - 0.002800735, - 0.002810772, - 0.002852313, - 0.002966118, - 0.003016746, - 0.002743067, - 0.002638638, - 0.002763653, - 0.003804955, - 0.005474943, - 0.00382094, - 0.00450423, - 0.004999363, - 0.007364651, - 0.006843461, - 0.006781604, - 0.006214453, - 0.005424738, - 0.005153085, - 0.004921373, - 0.00326591, - 0.006513757, - 0.001886535 - ], - [ - 0.012841934, - 0.009654454, - 0.009413148, - 0.009082606, - 0.009306265, - 0.009938136, - 0.011841703, - 0.010413312, - 0.013696353, - 0.010407472, - 0.00507324, - 0.003730826, - 0.005137215, - 0.004899509, - 0.003300001, - 0.00443726, - 0.007909457, - 0.004777845, - 0.005352928, - 0.004878104, - 0.005078607, - 0.005523185, - 0.004720603, - 0.004551434, - 0.004058308, - 0.001622267, - 0.002207851, - 0.008296074, - 0.005957308, - 0.005417293, - 0.004355405, - 0.00435013, - 0.005535804, - 0.00649752, - 0.009661387, - 0.005877275, - 0.003745508, - 0.004158974, - 0.003429219, - 0.003964473 - ], - [ - 0.006550588, - 0.003561567, - 0.004489165, - 0.003821699, - 0.003476525, - 0.004907308, - 0.003595231, - 0.00382739, - 0.007344817, - 0.00244224, - 0.002566996, - 0.002262381, - 0.002792209, - 0.002782429, - 0.003192869, - 0.003443725, - 0.002746027, - 0.003235998, - 0.003481887, - 0.003826154, - 0.004289188, - 0.005606518, - 0.006357923, - 0.005708005, - 0.005888416, - 0.005806738, - 0.00539865, - 0.005877065, - 0.00575867, - 0.005649567, - 0.006053352, - 0.00578508, - 0.005255661, - 0.009515703, - 0.006217025, - 0.005946889, - 0.007035902, - 0.007019097, - 0.007206557, - 0.005978009 - ], - [ - 0.009627581, - 0.012755989, - 0.008036376, - 0.007670786, - 0.007796472, - 0.008063767, - 0.008750194, - 0.005928886, - 0.005453439, - 0.004591073, - 0.004715627, - 0.005068282, - 0.005057351, - 0.005275064, - 0.00421776, - 0.004614465, - 0.004396804, - 0.008354557, - 0.004733246, - 0.004517265, - 0.004332668, - 0.001572626, - 0.004925422, - 0.00511866, - 0.005093805, - 0.004904462, - 0.005670728, - 0.005748364, - 0.004329005, - 0.006747785, - 0.006458118, - 0.006596252, - 0.006171283, - 0.006908023, - 0.00873379, - 0.006324814, - 0.006994502, - 0.005983618, - 0.007352112, - 0.00193365 - ], - [ - 0.012233163, - 0.008666409, - 0.009235241, - 0.008677243, - 0.008885789, - 0.006980572, - 0.009680923, - 0.004528205, - 0.006210358, - 0.003147615, - 0.003096247, - 0.003079493, - 0.003247813, - 0.003646477, - 0.003568133, - 0.004730613, - 0.007528038, - 0.005498424, - 0.005635506, - 0.004385524, - 0.004318678, - 0.005092201, - 0.00418213, - 0.004180973, - 0.004480327, - 0.004472983, - 0.005626828, - 0.008481945, - 0.008890724, - 0.010911213, - 0.01168713, - 0.004011501, - 0.006027824, - 0.001818208, - 0.001463402, - 0.00142202, - 0.001365819, - 0.001324493, - 0.001387998, - 0.00229958 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "true", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.015297531859999993, - "scoreError" : 0.0017528887459338854, - "scoreConfidence" : [ - 0.013544643114066108, - 0.01705042060593388 - ], - "scorePercentiles" : { - "0.0" : 0.007938051, - "50.0" : 0.0123956575, - "90.0" : 0.023920055800000003, - "95.0" : 0.029458214199999996, - "99.0" : 0.05354277871000004, - "99.9" : 0.053697946, - "99.99" : 0.053697946, - "99.999" : 0.053697946, - "99.9999" : 0.053697946, - "100.0" : 0.053697946 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.016091839, - 0.049296937, - 0.020452641, - 0.016261118, - 0.020526149, - 0.029080498, - 0.014299428, - 0.014683282, - 0.014380856, - 0.027963509, - 0.0125985, - 0.012717071, - 0.01490156, - 0.015090689, - 0.018437407, - 0.022348548, - 0.023314814, - 0.021719446, - 0.013752353, - 0.014248159, - 0.015815741, - 0.015056614, - 0.014389461, - 0.014336928, - 0.015702314, - 0.015269067, - 0.023829792, - 0.01097346, - 0.011871012, - 0.013536377, - 0.014394175, - 0.014118941, - 0.01489183, - 0.013445022, - 0.014552024, - 0.015391907, - 0.024437573, - 0.022028249, - 0.013782047, - 0.015195733 - ], - [ - 0.007938051, - 0.028587795, - 0.009884358, - 0.010693056, - 0.02065322, - 0.019383671, - 0.010550978, - 0.010763239, - 0.010160595, - 0.010348069, - 0.010363292, - 0.011239178, - 0.009253553, - 0.010731132, - 0.011416125, - 0.010375642, - 0.017706504, - 0.019124807, - 0.019727748, - 0.017247058, - 0.02192373, - 0.01041775, - 0.01016824, - 0.009811792, - 0.009780782, - 0.009349518, - 0.011584006, - 0.010665912, - 0.00920205, - 0.009353105, - 0.009551069, - 0.010452884, - 0.009892042, - 0.010048447, - 0.00934559, - 0.009586927, - 0.011409394, - 0.01038347, - 0.009615193, - 0.010754379 - ], - [ - 0.053697946, - 0.053585666, - 0.019147225, - 0.01344964, - 0.019000852, - 0.029478094, - 0.009852772, - 0.009843324, - 0.008920796, - 0.010844743, - 0.023925008, - 0.011192106, - 0.011250612, - 0.01056188, - 0.01059675, - 0.013221954, - 0.018835653, - 0.018463869, - 0.018888861, - 0.027757085, - 0.010406603, - 0.011985001, - 0.011477851, - 0.010606031, - 0.010395372, - 0.011283618, - 0.00991612, - 0.01089165, - 0.009210262, - 0.019798802, - 0.01126613, - 0.011605393, - 0.010586587, - 0.010403496, - 0.010268977, - 0.009844285, - 0.009632896, - 0.011279769, - 0.009332462, - 0.017246036 - ], - [ - 0.016392909, - 0.027868772, - 0.014091459, - 0.013653733, - 0.0230566, - 0.033998619, - 0.008276307, - 0.009297343, - 0.010682115, - 0.010001, - 0.024828619, - 0.010068719, - 0.011262854, - 0.011476861, - 0.010960941, - 0.017231498, - 0.02053801, - 0.021205937, - 0.018715171, - 0.010054456, - 0.010477726, - 0.010524627, - 0.010866467, - 0.011056118, - 0.009827978, - 0.011490291, - 0.011439137, - 0.011841831, - 0.010630085, - 0.009262964, - 0.011720648, - 0.01235113, - 0.01263014, - 0.010897814, - 0.011118128, - 0.011395425, - 0.011257814, - 0.011877345, - 0.023845011, - 0.021352685 - ], - [ - 0.031005038, - 0.0296674, - 0.022435752, - 0.035770359, - 0.034110246, - 0.012894558, - 0.012774599, - 0.012953484, - 0.027138715, - 0.010832197, - 0.011234659, - 0.010681414, - 0.012162823, - 0.016301853, - 0.023006459, - 0.020931346, - 0.031844194, - 0.013186971, - 0.011689507, - 0.012807172, - 0.013018013, - 0.012952755, - 0.01139102, - 0.012748749, - 0.023875486, - 0.012067214, - 0.012057717, - 0.012054535, - 0.012553962, - 0.011672718, - 0.011651334, - 0.011281899, - 0.014045736, - 0.020779907, - 0.027645977, - 0.011569217, - 0.01265288, - 0.013215314, - 0.012298122, - 0.012440185 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "true", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.1394670911450001, - "scoreError" : 0.005561584359133217, - "scoreConfidence" : [ - 0.1339055067858669, - 0.14502867550413331 - ], - "scorePercentiles" : { - "0.0" : 0.065366884, - "50.0" : 0.1335435405, - "90.0" : 0.18896439720000002, - "95.0" : 0.1953793825, - "99.0" : 0.20109828025999998, - "99.9" : 0.203656939, - "99.99" : 0.203656939, - "99.999" : 0.203656939, - "99.9999" : 0.203656939, - "100.0" : 0.203656939 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.138389912, - 0.133606361, - 0.133815531, - 0.127580577, - 0.133800152, - 0.116852138, - 0.134752523, - 0.131713225, - 0.129834328, - 0.128855887, - 0.134319342, - 0.132478596, - 0.133375666, - 0.132287073, - 0.130492526, - 0.134636162, - 0.129917835, - 0.131900031, - 0.133157621, - 0.130798565, - 0.189083566, - 0.185021802, - 0.131802466, - 0.133639512, - 0.13265301, - 0.130074401, - 0.184273754, - 0.184997653, - 0.135807718, - 0.133420392, - 0.130545856, - 0.185229232, - 0.185309382, - 0.13521803, - 0.1332913, - 0.133345741, - 0.132311493, - 0.135768367, - 0.137217399, - 0.135017868 - ], - [ - 0.133339576, - 0.129513723, - 0.12706378, - 0.126376614, - 0.128082218, - 0.125138284, - 0.12173485, - 0.124374596, - 0.12113211, - 0.125102845, - 0.123980221, - 0.065366884, - 0.121232977, - 0.125897141, - 0.122150275, - 0.130318476, - 0.127014078, - 0.130445016, - 0.128840012, - 0.125716169, - 0.126810782, - 0.121818442, - 0.127555813, - 0.125874834, - 0.065456111, - 0.124733542, - 0.112045189, - 0.123963784, - 0.123226149, - 0.124514148, - 0.126168262, - 0.128130648, - 0.131340729, - 0.126942378, - 0.131849318, - 0.127362959, - 0.123878473, - 0.12343337, - 0.121928254, - 0.127795583 - ], - [ - 0.191913835, - 0.193681136, - 0.141051321, - 0.138470864, - 0.13901043, - 0.197198595, - 0.13813479, - 0.140200931, - 0.192813127, - 0.138051841, - 0.138152666, - 0.138079293, - 0.193990125, - 0.141130448, - 0.140589174, - 0.134457975, - 0.134593432, - 0.190207351, - 0.13360224, - 0.135875118, - 0.136834113, - 0.137448304, - 0.133561771, - 0.138357134, - 0.194941081, - 0.141303946, - 0.138574492, - 0.137603818, - 0.140179848, - 0.083506814, - 0.200471459, - 0.200638451, - 0.198133712, - 0.139805835, - 0.141489202, - 0.140057896, - 0.201102925, - 0.141802355, - 0.140531924, - 0.136821508 - ], - [ - 0.195639292, - 0.138449345, - 0.138388931, - 0.138188079, - 0.136454968, - 0.195402451, - 0.135657465, - 0.136644087, - 0.137661258, - 0.139170104, - 0.13734865, - 0.203656939, - 0.135681264, - 0.137388028, - 0.137773551, - 0.136722358, - 0.137446342, - 0.139122609, - 0.13591835, - 0.138103479, - 0.192776419, - 0.134472864, - 0.129948541, - 0.135018531, - 0.136552361, - 0.13352531, - 0.196178481, - 0.190184376, - 0.137683502, - 0.138520058, - 0.138259343, - 0.192247612, - 0.137892593, - 0.143029334, - 0.19883127, - 0.138818718, - 0.141140657, - 0.142204775, - 0.139063395, - 0.141538083 - ], - [ - 0.135971459, - 0.130182658, - 0.132372294, - 0.128237162, - 0.131605103, - 0.127554761, - 0.131357032, - 0.128161778, - 0.131456045, - 0.13065343, - 0.12916806, - 0.118939687, - 0.122342932, - 0.12175042, - 0.120370439, - 0.129844029, - 0.129606532, - 0.128877233, - 0.130871872, - 0.130221551, - 0.129273574, - 0.12906997, - 0.130487079, - 0.128566312, - 0.185032746, - 0.130984252, - 0.12990251, - 0.132026913, - 0.117951882, - 0.121926151, - 0.118015764, - 0.122246377, - 0.114980206, - 0.132146913, - 0.131145432, - 0.12840629, - 0.186197532, - 0.187891878, - 0.129016787, - 0.131288525 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "false", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 5.995485000000002E-4, - "scoreError" : 4.3811027574123626E-5, - "scoreConfidence" : [ - 5.557374724258766E-4, - 6.433595275741237E-4 - ], - "scorePercentiles" : { - "0.0" : 4.1263E-4, - "50.0" : 4.99108E-4, - "90.0" : 8.78052E-4, - "95.0" : 9.06207E-4, - "99.0" : 0.001177053710000001, - "99.9" : 0.001307484, - "99.99" : 0.001307484, - "99.999" : 0.001307484, - "99.9999" : 0.001307484, - "100.0" : 0.001307484 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 9.09312E-4, - 8.96418E-4, - 8.9805E-4, - 0.001069709, - 8.62951E-4, - 8.60436E-4, - 8.4283E-4, - 8.41191E-4, - 8.43014E-4, - 8.42838E-4, - 5.48278E-4, - 4.92646E-4, - 4.73484E-4, - 4.55155E-4, - 5.16996E-4, - 6.57916E-4, - 5.17258E-4, - 5.71327E-4, - 4.71826E-4, - 5.04444E-4, - 5.64807E-4, - 4.95505E-4, - 7.0239E-4, - 7.35321E-4, - 4.58599E-4, - 5.50358E-4, - 4.52428E-4, - 4.7045E-4, - 5.68751E-4, - 7.75605E-4, - 4.70967E-4, - 5.85284E-4, - 4.28146E-4, - 4.29809E-4, - 4.24379E-4, - 5.65845E-4, - 4.68845E-4, - 4.78282E-4, - 4.33486E-4, - 4.62641E-4 - ], - [ - 9.17283E-4, - 8.76052E-4, - 0.001178138, - 9.29679E-4, - 8.46595E-4, - 8.31428E-4, - 8.53784E-4, - 8.23317E-4, - 8.49367E-4, - 8.38556E-4, - 6.26661E-4, - 7.01677E-4, - 4.8409E-4, - 5.36346E-4, - 4.39889E-4, - 4.94242E-4, - 5.00033E-4, - 7.18989E-4, - 4.99816E-4, - 4.8757E-4, - 5.15734E-4, - 4.6654E-4, - 5.0994E-4, - 4.73405E-4, - 4.88727E-4, - 4.30407E-4, - 4.32691E-4, - 6.87903E-4, - 4.8747E-4, - 4.90962E-4, - 4.83247E-4, - 5.48422E-4, - 4.38452E-4, - 4.83202E-4, - 4.35573E-4, - 4.23706E-4, - 4.44933E-4, - 4.6728E-4, - 4.83074E-4, - 5.13567E-4 - ], - [ - 8.78717E-4, - 8.78156E-4, - 8.77116E-4, - 0.001011923, - 8.64496E-4, - 8.43609E-4, - 8.2489E-4, - 8.69808E-4, - 8.28512E-4, - 8.33783E-4, - 5.37635E-4, - 4.93759E-4, - 4.90737E-4, - 5.07813E-4, - 4.55646E-4, - 4.49982E-4, - 7.74651E-4, - 5.27461E-4, - 5.10173E-4, - 5.52446E-4, - 4.98783E-4, - 4.83858E-4, - 4.79983E-4, - 4.6022E-4, - 4.56073E-4, - 4.68984E-4, - 4.67474E-4, - 4.58902E-4, - 4.54669E-4, - 4.43207E-4, - 5.02687E-4, - 4.61893E-4, - 4.9928E-4, - 4.40323E-4, - 4.1263E-4, - 4.95644E-4, - 4.98936E-4, - 4.50939E-4, - 4.53023E-4, - 5.04189E-4 - ], - [ - 9.03349E-4, - 9.05124E-4, - 8.84912E-4, - 9.01179E-4, - 9.11628E-4, - 8.85275E-4, - 8.581E-4, - 8.41694E-4, - 8.25247E-4, - 8.22008E-4, - 6.35483E-4, - 4.7404E-4, - 4.71033E-4, - 5.06415E-4, - 4.43261E-4, - 5.20316E-4, - 5.02368E-4, - 5.22061E-4, - 7.14331E-4, - 4.55165E-4, - 5.14315E-4, - 5.23846E-4, - 7.25892E-4, - 4.75041E-4, - 4.62001E-4, - 4.47029E-4, - 4.3225E-4, - 4.33559E-4, - 4.64835E-4, - 4.57728E-4, - 4.36406E-4, - 6.95275E-4, - 4.8761E-4, - 4.63498E-4, - 4.24973E-4, - 4.22708E-4, - 4.66357E-4, - 4.81153E-4, - 4.88443E-4, - 4.38868E-4 - ], - [ - 8.7068E-4, - 8.85252E-4, - 8.65807E-4, - 9.38228E-4, - 0.001307484, - 9.06264E-4, - 8.36557E-4, - 8.48087E-4, - 8.44631E-4, - 7.52699E-4, - 4.8588E-4, - 4.98458E-4, - 4.91668E-4, - 4.85502E-4, - 4.53113E-4, - 4.881E-4, - 8.65157E-4, - 5.18107E-4, - 4.71175E-4, - 4.7828E-4, - 4.9821E-4, - 5.01583E-4, - 4.77148E-4, - 6.02888E-4, - 4.39428E-4, - 4.46347E-4, - 4.49457E-4, - 4.77644E-4, - 4.3548E-4, - 4.46334E-4, - 4.42237E-4, - 7.08187E-4, - 4.59639E-4, - 4.66112E-4, - 4.75616E-4, - 4.92632E-4, - 4.52272E-4, - 4.66284E-4, - 5.4001E-4, - 4.76553E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "false", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.0033590787249999977, - "scoreError" : 2.2883441180497608E-4, - "scoreConfidence" : [ - 0.0031302443131950215, - 0.003587913136804974 - ], - "scorePercentiles" : { - "0.0" : 0.002338135, - "50.0" : 0.0029826799999999997, - "90.0" : 0.0054030626, - "95.0" : 0.0056766622, - "99.0" : 0.0058792778, - "99.9" : 0.006176461, - "99.99" : 0.006176461, - "99.999" : 0.006176461, - "99.9999" : 0.006176461, - "100.0" : 0.006176461 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.002877173, - 0.002964541, - 0.00271126, - 0.002488611, - 0.002682502, - 0.002581103, - 0.002475452, - 0.002338135, - 0.002415493, - 0.002797327, - 0.002656093, - 0.005229567, - 0.002829109, - 0.00305368, - 0.002834016, - 0.002910597, - 0.002949168, - 0.003032279, - 0.003110529, - 0.003295983, - 0.003411963, - 0.003077778, - 0.003095952, - 0.00290352, - 0.002897497, - 0.004283789, - 0.006176461, - 0.00570984, - 0.005403782, - 0.005623128, - 0.005666444, - 0.00284668, - 0.002878422, - 0.003123018, - 0.002746507, - 0.00279399, - 0.002762446, - 0.002789284, - 0.002839318, - 0.003125176 - ], - [ - 0.003294998, - 0.002971148, - 0.002599587, - 0.00263863, - 0.002656358, - 0.002739583, - 0.002760506, - 0.002716349, - 0.00330579, - 0.00312017, - 0.002978111, - 0.004968882, - 0.002846725, - 0.003060808, - 0.002827978, - 0.002884636, - 0.003032405, - 0.003864794, - 0.003010449, - 0.003174228, - 0.003175336, - 0.002982805, - 0.002940462, - 0.003209891, - 0.002979653, - 0.004139421, - 0.005816253, - 0.005344107, - 0.005482821, - 0.005444671, - 0.00579674, - 0.003005804, - 0.0029959, - 0.00319083, - 0.002884261, - 0.003021521, - 0.002935089, - 0.002902524, - 0.002798391, - 0.002801912 - ], - [ - 0.003556441, - 0.002668212, - 0.002509497, - 0.002758424, - 0.002625785, - 0.002809196, - 0.00243878, - 0.002714381, - 0.002788249, - 0.002959212, - 0.002987659, - 0.005127495, - 0.002870219, - 0.00300401, - 0.003221705, - 0.003169477, - 0.003026786, - 0.0029358, - 0.003053179, - 0.003093566, - 0.00306252, - 0.003111844, - 0.003017019, - 0.003143228, - 0.003036338, - 0.004292354, - 0.005593819, - 0.005864903, - 0.005305052, - 0.005396588, - 0.0056772, - 0.003269773, - 0.002982555, - 0.003147997, - 0.00297643, - 0.002861309, - 0.002885775, - 0.003270091, - 0.002976806, - 0.002919162 - ], - [ - 0.003133565, - 0.002768015, - 0.002533229, - 0.002521832, - 0.002524315, - 0.00268365, - 0.00244519, - 0.002764592, - 0.002562486, - 0.002681475, - 0.002956682, - 0.005249239, - 0.002918952, - 0.003097977, - 0.002910871, - 0.002987776, - 0.003061213, - 0.002926952, - 0.002929002, - 0.004000134, - 0.002948482, - 0.002993532, - 0.00298166, - 0.003086946, - 0.002833489, - 0.00425494, - 0.005879423, - 0.005702393, - 0.005424634, - 0.005575865, - 0.00586101, - 0.00332398, - 0.003005177, - 0.002996818, - 0.003075799, - 0.002961008, - 0.002836705, - 0.00286268, - 0.002904246, - 0.002952987 - ], - [ - 0.003258246, - 0.003114742, - 0.002573933, - 0.00272855, - 0.002599796, - 0.002710636, - 0.002767612, - 0.002606023, - 0.002757796, - 0.003005304, - 0.003092639, - 0.004950241, - 0.002904051, - 0.002846642, - 0.003047134, - 0.002904974, - 0.00317278, - 0.003171981, - 0.003111432, - 0.002970304, - 0.003161164, - 0.002963184, - 0.003050264, - 0.003062605, - 0.003644738, - 0.004424614, - 0.005643728, - 0.005451883, - 0.005356556, - 0.005267834, - 0.005809954, - 0.003145508, - 0.002963437, - 0.002970176, - 0.002834618, - 0.002828244, - 0.002939351, - 0.003332585, - 0.002917954, - 0.002836635 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "false", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.028548966145, - "scoreError" : 0.002361969929034401, - "scoreConfidence" : [ - 0.0261869962159656, - 0.0309109360740344 - ], - "scorePercentiles" : { - "0.0" : 0.018257454, - "50.0" : 0.0227511165, - "90.0" : 0.043766564800000005, - "95.0" : 0.04797810649999998, - "99.0" : 0.05609701992000002, - "99.9" : 0.056620122, - "99.99" : 0.056620122, - "99.999" : 0.056620122, - "99.9999" : 0.056620122, - "100.0" : 0.056620122 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.033321169, - 0.056620122, - 0.022155144, - 0.023435985, - 0.034680287, - 0.024028336, - 0.022759512, - 0.024060928, - 0.043148864, - 0.042386026, - 0.048053451, - 0.022609102, - 0.023365449, - 0.021807837, - 0.023913786, - 0.022066993, - 0.033449492, - 0.022684993, - 0.023596132, - 0.022600578, - 0.021383416, - 0.021924622, - 0.021799295, - 0.04368011, - 0.04500344, - 0.043707803, - 0.046546561, - 0.043356143, - 0.03985297, - 0.022656711, - 0.021887239, - 0.019476651, - 0.019368614, - 0.019123873, - 0.023275754, - 0.022084631, - 0.021987245, - 0.021604357, - 0.020791597, - 0.021484423 - ], - [ - 0.032962175, - 0.053660626, - 0.022524115, - 0.022742721, - 0.03369467, - 0.022611996, - 0.022702836, - 0.021177545, - 0.042041322, - 0.043820144, - 0.048988603, - 0.021933086, - 0.021662298, - 0.019025546, - 0.020992788, - 0.020400362, - 0.033034607, - 0.022609244, - 0.021642933, - 0.018861292, - 0.019643362, - 0.021167322, - 0.025688834, - 0.044844581, - 0.043905004, - 0.044690654, - 0.043014107, - 0.041950132, - 0.037715781, - 0.022220061, - 0.019965622, - 0.022269483, - 0.022765994, - 0.021294116, - 0.021732861, - 0.023280973, - 0.022281421, - 0.021156484, - 0.020687223, - 0.019360721 - ], - [ - 0.033623266, - 0.056110416, - 0.0223513, - 0.022160857, - 0.032935524, - 0.023282482, - 0.022975439, - 0.021510169, - 0.043152302, - 0.042834967, - 0.049633088, - 0.022956822, - 0.021893622, - 0.02215369, - 0.018843504, - 0.021395929, - 0.031825565, - 0.022536871, - 0.022555892, - 0.021373561, - 0.02345346, - 0.021760739, - 0.026745433, - 0.043769051, - 0.042623192, - 0.042333155, - 0.040926241, - 0.041139323, - 0.041216933, - 0.022946504, - 0.021822309, - 0.02223811, - 0.021940757, - 0.021704181, - 0.021229267, - 0.021245882, - 0.018257454, - 0.019833693, - 0.021981706, - 0.021970316 - ], - [ - 0.032573722, - 0.051056344, - 0.021544809, - 0.020921648, - 0.032257743, - 0.020698229, - 0.022679836, - 0.022000916, - 0.042818941, - 0.041562864, - 0.050404721, - 0.023854128, - 0.024769901, - 0.023051267, - 0.022810773, - 0.023806201, - 0.032795133, - 0.022294033, - 0.022140018, - 0.022514829, - 0.022831558, - 0.023248216, - 0.027154392, - 0.043203974, - 0.042541912, - 0.044434497, - 0.043495609, - 0.044205836, - 0.041017955, - 0.022228433, - 0.022662191, - 0.021146539, - 0.021759629, - 0.022345871, - 0.022048927, - 0.021787409, - 0.02442681, - 0.022386888, - 0.022606985, - 0.020513049 - ], - [ - 0.034835203, - 0.054770808, - 0.021815727, - 0.020960544, - 0.031434751, - 0.022259573, - 0.022531367, - 0.021299145, - 0.043744189, - 0.042444983, - 0.048608254, - 0.021945358, - 0.023319623, - 0.023008105, - 0.021561457, - 0.022539353, - 0.030842017, - 0.01975482, - 0.018609186, - 0.018446606, - 0.022500199, - 0.02220664, - 0.026513119, - 0.042419737, - 0.043112526, - 0.043901027, - 0.043050783, - 0.043659248, - 0.037913924, - 0.023123305, - 0.022880943, - 0.021480728, - 0.022682691, - 0.022539017, - 0.025836093, - 0.022488167, - 0.024740308, - 0.02299647, - 0.02152549, - 0.023182751 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Vector", - "parallel" : "false", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.33812204633999987, - "scoreError" : 0.008935037718009917, - "scoreConfidence" : [ - 0.32918700862198996, - 0.3470570840580098 - ], - "scorePercentiles" : { - "0.0" : 0.235896495, - "50.0" : 0.3410437895, - "90.0" : 0.3885304773, - "95.0" : 0.39652561714999995, - "99.0" : 0.41454341450000004, - "99.9" : 0.418991813, - "99.99" : 0.418991813, - "99.999" : 0.418991813, - "99.9999" : 0.418991813, - "100.0" : 0.418991813 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.342093026, - 0.387516914, - 0.326219325, - 0.337432308, - 0.33661248, - 0.298680331, - 0.313264843, - 0.271589633, - 0.332673078, - 0.323285786, - 0.388438041, - 0.301151511, - 0.38977224, - 0.284503141, - 0.305133628, - 0.390313584, - 0.314577757, - 0.355034184, - 0.347236991, - 0.277200011, - 0.364261236, - 0.343187015, - 0.379126969, - 0.32893314, - 0.255661742, - 0.316889209, - 0.372155795, - 0.307432953, - 0.296853199, - 0.414594238, - 0.327905279, - 0.327623572, - 0.37682016, - 0.34634173, - 0.344464155, - 0.265281839, - 0.348003983, - 0.39553306, - 0.315187049, - 0.318031067 - ], - [ - 0.364971291, - 0.339138904, - 0.388540748, - 0.37258119, - 0.356577545, - 0.345565283, - 0.366139553, - 0.324415893, - 0.370318084, - 0.306486544, - 0.279801314, - 0.346808415, - 0.328153876, - 0.297630112, - 0.364565535, - 0.285623638, - 0.318729965, - 0.341912391, - 0.302184921, - 0.304837157, - 0.255135811, - 0.349863101, - 0.37558794, - 0.235896495, - 0.318089243, - 0.357636483, - 0.292898008, - 0.289989634, - 0.337635305, - 0.287767523, - 0.289916549, - 0.319584319, - 0.29952012, - 0.304442635, - 0.291783061, - 0.317346841, - 0.384262538, - 0.379689207, - 0.301660539, - 0.285711925 - ], - [ - 0.418991813, - 0.396577857, - 0.308937398, - 0.384051514, - 0.370446763, - 0.331641206, - 0.310952361, - 0.319887921, - 0.337878072, - 0.269732297, - 0.361431234, - 0.347245322, - 0.247511306, - 0.341677068, - 0.383329377, - 0.298623444, - 0.327648602, - 0.360836457, - 0.409511888, - 0.316063334, - 0.306807078, - 0.332792462, - 0.294556047, - 0.322018396, - 0.378641946, - 0.29611869, - 0.356943874, - 0.375451114, - 0.293234972, - 0.305354315, - 0.368381309, - 0.321551853, - 0.321856353, - 0.260577148, - 0.337315457, - 0.392133247, - 0.247980688, - 0.341859904, - 0.352415202, - 0.341527731 - ], - [ - 0.366637619, - 0.388349589, - 0.362922839, - 0.404337396, - 0.330562974, - 0.314245355, - 0.378472477, - 0.328182757, - 0.353648848, - 0.364375202, - 0.355936447, - 0.34596796, - 0.384869411, - 0.351148594, - 0.357268504, - 0.340773046, - 0.328286303, - 0.255215052, - 0.345142157, - 0.347547195, - 0.303692577, - 0.407633385, - 0.341350046, - 0.35230339, - 0.328065602, - 0.332535908, - 0.375088295, - 0.31822945, - 0.373583163, - 0.368044564, - 0.330608235, - 0.390542753, - 0.318272837, - 0.374287045, - 0.359425918, - 0.318131691, - 0.380266411, - 0.314482553, - 0.381401684, - 0.343049096 - ], - [ - 0.408358854, - 0.341314533, - 0.392884054, - 0.393975352, - 0.329816002, - 0.309388802, - 0.398568259, - 0.302368436, - 0.401914463, - 0.344675603, - 0.266296557, - 0.349582678, - 0.360614758, - 0.306354915, - 0.379133577, - 0.354990931, - 0.319193733, - 0.366900901, - 0.316787723, - 0.380950543, - 0.295440268, - 0.343846034, - 0.300243568, - 0.316867292, - 0.332712893, - 0.312998796, - 0.372216698, - 0.34565015, - 0.358079794, - 0.372810132, - 0.333794337, - 0.297097653, - 0.392795641, - 0.323786548, - 0.389326625, - 0.397349878, - 0.371825989, - 0.350302661, - 0.346305938, - 0.295094513 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "true", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.0019311214249999997, - "scoreError" : 2.581467856604888E-4, - "scoreConfidence" : [ - 0.0016729746393395108, - 0.0021892682106604885 - ], - "scorePercentiles" : { - "0.0" : 7.22028E-4, - "50.0" : 0.0017527965, - "90.0" : 0.0029240778000000005, - "95.0" : 0.0040117907999999945, - "99.0" : 0.0071250767600000015, - "99.9" : 0.007211743, - "99.99" : 0.007211743, - "99.999" : 0.007211743, - "99.9999" : 0.007211743, - "100.0" : 0.007211743 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.003438995, - 0.003287572, - 0.003526964, - 0.003474722, - 0.007211743, - 0.00318312, - 0.003001037, - 0.00297613, - 0.002878833, - 0.002929105, - 0.002797614, - 0.002681322, - 0.002448165, - 0.002644985, - 0.002335916, - 0.002577817, - 0.002435778, - 0.002556022, - 0.002446008, - 0.002428395, - 0.002436332, - 0.004461362, - 0.002380892, - 0.002403031, - 0.002526184, - 0.002466198, - 0.002561378, - 0.002550068, - 0.002480788, - 0.002555589, - 0.002557914, - 0.002589569, - 0.002695867, - 0.002279208, - 0.002409531, - 0.002502492, - 0.002455017, - 0.002635101, - 0.004537263, - 0.002386191 - ], - [ - 0.00223998, - 0.001717037, - 0.0018429, - 0.001830508, - 0.002025014, - 0.00634829, - 0.001645315, - 0.001560929, - 0.001677505, - 0.001606667, - 0.001272457, - 0.001212776, - 0.001182727, - 0.001162923, - 0.001184407, - 9.82962E-4, - 0.001088722, - 0.001038551, - 8.19815E-4, - 8.75461E-4, - 8.33282E-4, - 9.38594E-4, - 0.003133062, - 7.5407E-4, - 8.38692E-4, - 7.22028E-4, - 9.63488E-4, - 9.26756E-4, - 9.27792E-4, - 8.03332E-4, - 9.05728E-4, - 0.00108958, - 0.001067203, - 8.06819E-4, - 8.66995E-4, - 8.31197E-4, - 8.75188E-4, - 8.54788E-4, - 8.51359E-4, - 9.52285E-4 - ], - [ - 0.002100083, - 0.002219826, - 0.001744402, - 0.001761191, - 0.00200418, - 0.007126856, - 0.001663481, - 0.001454366, - 0.001474794, - 0.001438248, - 0.001471725, - 0.001426621, - 0.001459791, - 0.001182723, - 0.001139211, - 0.001136371, - 0.001238742, - 0.001096799, - 8.77593E-4, - 8.16532E-4, - 9.28243E-4, - 9.65967E-4, - 8.96061E-4, - 0.00299155, - 7.751E-4, - 0.001023217, - 0.001301657, - 0.001002482, - 0.00100555, - 8.10623E-4, - 0.001094386, - 0.001166318, - 0.001093763, - 9.78387E-4, - 9.91325E-4, - 9.18046E-4, - 8.76184E-4, - 8.62523E-4, - 8.86384E-4, - 0.001001331 - ], - [ - 0.002385361, - 0.002239723, - 0.002302068, - 0.002443578, - 0.002487335, - 0.005975799, - 0.004037308, - 0.001443651, - 0.001488201, - 0.001403017, - 0.001471449, - 0.001502091, - 0.001465842, - 0.001509798, - 0.001514903, - 0.001503797, - 0.001516608, - 0.001450257, - 0.001425322, - 0.001430862, - 0.001453649, - 0.001655935, - 0.004788347, - 0.001407111, - 0.001429409, - 0.001379343, - 0.001359846, - 0.001381112, - 0.001343155, - 0.00132694, - 0.001486503, - 0.00149798, - 0.00145779, - 0.001414666, - 0.001454894, - 0.001403387, - 0.001390769, - 0.001432656, - 0.001423493, - 0.001524704 - ], - [ - 0.002388682, - 0.002254763, - 0.002206791, - 0.002576203, - 0.002545365, - 0.006948932, - 0.00210295, - 0.002035217, - 0.002048518, - 0.002078521, - 0.001920648, - 0.001961473, - 0.001850246, - 0.001934272, - 0.001924632, - 0.001871455, - 0.001953285, - 0.001978449, - 0.001902089, - 0.002035761, - 0.002042961, - 0.001985014, - 0.004143489, - 0.001871932, - 0.001905894, - 0.001908879, - 0.001864086, - 0.001892639, - 0.001956538, - 0.001997635, - 0.00198924, - 0.001859654, - 0.001865424, - 0.001880294, - 0.001820568, - 0.001843857, - 0.001902989, - 0.002169097, - 0.002567837, - 0.002439313 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "true", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.0077740972300000015, - "scoreError" : 7.774046101135125E-4, - "scoreConfidence" : [ - 0.006996692619886489, - 0.008551501840113515 - ], - "scorePercentiles" : { - "0.0" : 0.003221562, - "50.0" : 0.0064685639999999996, - "90.0" : 0.0130453246, - "95.0" : 0.013863231149999999, - "99.0" : 0.01622279343000001, - "99.9" : 0.019205396, - "99.99" : 0.019205396, - "99.999" : 0.019205396, - "99.9999" : 0.019205396, - "100.0" : 0.019205396 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.006184692, - 0.011149621, - 0.010380799, - 0.005353152, - 0.009244765, - 0.006318136, - 0.005484814, - 0.008166673, - 0.013701671, - 0.013414709, - 0.008398444, - 0.00590333, - 0.006354795, - 0.004706735, - 0.005433055, - 0.010443713, - 0.006420128, - 0.007721129, - 0.008213409, - 0.00773834, - 0.008610775, - 0.013118168, - 0.012984544, - 0.013726282, - 0.012868717, - 0.016234985, - 0.006314774, - 0.005316236, - 0.004733261, - 0.004041631, - 0.005237632, - 0.005009668, - 0.005800346, - 0.004143962, - 0.004514739, - 0.004890068, - 0.004697828, - 0.00521894, - 0.004423739, - 0.005442587 - ], - [ - 0.005919041, - 0.00939828, - 0.008951059, - 0.005512273, - 0.005526655, - 0.012403164, - 0.006727349, - 0.00541284, - 0.011782629, - 0.01458573, - 0.01267038, - 0.005918082, - 0.006597298, - 0.00436097, - 0.00517831, - 0.007393953, - 0.005677813, - 0.005503386, - 0.004527958, - 0.004600914, - 0.005762437, - 0.008484274, - 0.013052078, - 0.012488095, - 0.0103492, - 0.013218289, - 0.011198148, - 0.007486545, - 0.004723468, - 0.003952048, - 0.003762539, - 0.004325287, - 0.003560064, - 0.003535279, - 0.005072565, - 0.005301311, - 0.004873167, - 0.003221562, - 0.004945383, - 0.003986462 - ], - [ - 0.005467842, - 0.009923203, - 0.010020436, - 0.005636096, - 0.006382383, - 0.005088901, - 0.006386559, - 0.006859752, - 0.012169183, - 0.01407988, - 0.019205396, - 0.013598231, - 0.013463946, - 0.007124382, - 0.006114051, - 0.009068134, - 0.006660874, - 0.008225563, - 0.007174849, - 0.008008449, - 0.009026274, - 0.008355254, - 0.012231678, - 0.013984188, - 0.012355045, - 0.013993814, - 0.012862891, - 0.004855557, - 0.004128046, - 0.005594873, - 0.005787502, - 0.005125544, - 0.005047702, - 0.004922833, - 0.006286002, - 0.004947891, - 0.00503848, - 0.005264627, - 0.007190634, - 0.005090064 - ], - [ - 0.006655153, - 0.010510892, - 0.010499649, - 0.006256306, - 0.011592365, - 0.006840721, - 0.007131297, - 0.007813631, - 0.012859899, - 0.013870439, - 0.012128241, - 0.005293783, - 0.005065081, - 0.005086736, - 0.005954945, - 0.007480891, - 0.004856366, - 0.004357535, - 0.003966016, - 0.005804198, - 0.005664668, - 0.009343946, - 0.012595142, - 0.012586218, - 0.011059198, - 0.012830904, - 0.014338467, - 0.005181926, - 0.010421356, - 0.003806721, - 0.003576632, - 0.003777159, - 0.007286072, - 0.006390003, - 0.003660307, - 0.004810099, - 0.004291075, - 0.005044625, - 0.005177691, - 0.005431847 - ], - [ - 0.00768719, - 0.010778832, - 0.015015828, - 0.008961086, - 0.008880138, - 0.006583795, - 0.006816962, - 0.006268976, - 0.010972496, - 0.011885224, - 0.013144101, - 0.005194025, - 0.005142446, - 0.006089188, - 0.005880408, - 0.006726654, - 0.005780033, - 0.005697055, - 0.005183754, - 0.004844065, - 0.006108478, - 0.008482291, - 0.014598754, - 0.013528449, - 0.010353177, - 0.012671933, - 0.011657734, - 0.007053612, - 0.006022251, - 0.00657669, - 0.006517, - 0.006202447, - 0.006310511, - 0.006900614, - 0.008998486, - 0.009389102, - 0.008986061, - 0.006079702, - 0.008458768, - 0.008338644 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "true", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.05356017676999999, - "scoreError" : 0.002683233136911231, - "scoreConfidence" : [ - 0.050876943633088756, - 0.05624340990691122 - ], - "scorePercentiles" : { - "0.0" : 0.040454625, - "50.0" : 0.051441696999999995, - "90.0" : 0.0547258154, - "95.0" : 0.0896250312499996, - "99.0" : 0.10987401329000002, - "99.9" : 0.11006534, - "99.99" : 0.11006534, - "99.999" : 0.11006534, - "99.9999" : 0.11006534, - "100.0" : 0.11006534 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.105976799, - 0.043071397, - 0.056442983, - 0.050363179, - 0.051227534, - 0.093562052, - 0.04287326, - 0.051222915, - 0.05530708, - 0.051787845, - 0.053923789, - 0.050161402, - 0.051565252, - 0.055115184, - 0.051373352, - 0.051370398, - 0.053368462, - 0.051605117, - 0.054614359, - 0.051665182, - 0.050751919, - 0.055162909, - 0.051789058, - 0.049753505, - 0.053624546, - 0.05116246, - 0.05424964, - 0.051982283, - 0.049450504, - 0.054411175, - 0.051719679, - 0.050074716, - 0.05338739, - 0.049680151, - 0.054628943, - 0.051722419, - 0.05015371, - 0.053985267, - 0.050974952, - 0.051814327 - ], - [ - 0.11006534, - 0.042519379, - 0.055295802, - 0.050780761, - 0.050584745, - 0.091365824, - 0.042308933, - 0.050211995, - 0.054736579, - 0.051075235, - 0.048561622, - 0.053885438, - 0.050509352, - 0.052346484, - 0.05152291, - 0.050817565, - 0.053343376, - 0.048574713, - 0.050846728, - 0.051596715, - 0.050769057, - 0.052657159, - 0.050854064, - 0.050334749, - 0.054208913, - 0.051005687, - 0.048793388, - 0.053533992, - 0.04942728, - 0.050481989, - 0.050406909, - 0.050230263, - 0.054202588, - 0.050122286, - 0.050345737, - 0.054013849, - 0.051064239, - 0.048001092, - 0.052246003, - 0.049515415 - ], - [ - 0.107794448, - 0.041929524, - 0.048742969, - 0.053397717, - 0.048240094, - 0.091898433, - 0.040454625, - 0.048351955, - 0.05213859, - 0.049801913, - 0.046645815, - 0.053323615, - 0.049178943, - 0.048942673, - 0.050294388, - 0.048971153, - 0.049200713, - 0.05169512, - 0.046675965, - 0.050382817, - 0.04868846, - 0.046626353, - 0.052203863, - 0.049026219, - 0.048735126, - 0.050171878, - 0.04958576, - 0.047547928, - 0.052411311, - 0.04844274, - 0.048208101, - 0.048516897, - 0.046716373, - 0.051318341, - 0.047954184, - 0.048022638, - 0.05223091, - 0.049253761, - 0.048850822, - 0.051714716 - ], - [ - 0.109895019, - 0.050559504, - 0.056549969, - 0.050222797, - 0.051890611, - 0.093412477, - 0.042561325, - 0.050549039, - 0.054872111, - 0.050564393, - 0.053921319, - 0.051997189, - 0.05041204, - 0.054546669, - 0.052596373, - 0.051809683, - 0.054071173, - 0.05141737, - 0.053695557, - 0.05211303, - 0.050647934, - 0.053632471, - 0.051435743, - 0.0510815, - 0.054139599, - 0.051124476, - 0.053900662, - 0.049279777, - 0.050881747, - 0.052810726, - 0.051657237, - 0.051474031, - 0.053810242, - 0.051700478, - 0.053591563, - 0.052031486, - 0.051203385, - 0.05446077, - 0.051744091, - 0.049013481 - ], - [ - 0.10752703, - 0.043222236, - 0.056097194, - 0.049632174, - 0.051447651, - 0.097938756, - 0.043106313, - 0.050920335, - 0.054508336, - 0.049984125, - 0.053597574, - 0.052189038, - 0.051898606, - 0.054544559, - 0.049624767, - 0.050415607, - 0.052868254, - 0.051882118, - 0.053382577, - 0.050449686, - 0.051914767, - 0.053926279, - 0.051880741, - 0.05128929, - 0.054051513, - 0.05171086, - 0.053785397, - 0.05207461, - 0.05140608, - 0.054993009, - 0.0519688, - 0.050302304, - 0.05312603, - 0.05149967, - 0.053784632, - 0.051426406, - 0.04988047, - 0.054397975, - 0.051786432, - 0.049785006 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "true", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 0.5284585583950004, - "scoreError" : 0.004011753822879868, - "scoreConfidence" : [ - 0.5244468045721206, - 0.5324703122178803 - ], - "scorePercentiles" : { - "0.0" : 0.498086095, - "50.0" : 0.531935594, - "90.0" : 0.5474746769, - "95.0" : 0.5507595724, - "99.0" : 0.5842884550300003, - "99.9" : 0.593475199, - "99.99" : 0.593475199, - "99.999" : 0.593475199, - "99.9999" : 0.593475199, - "100.0" : 0.593475199 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.547994816, - 0.538239975, - 0.542213435, - 0.539532579, - 0.542205389, - 0.51092591, - 0.558552369, - 0.523067942, - 0.555563533, - 0.525257712, - 0.542078858, - 0.512516336, - 0.547485428, - 0.517350076, - 0.542135117, - 0.514838571, - 0.53540211, - 0.507587339, - 0.548132413, - 0.515233769, - 0.543121253, - 0.512654308, - 0.548081694, - 0.511649038, - 0.542116491, - 0.51719666, - 0.544002634, - 0.516980177, - 0.543596718, - 0.519802485, - 0.54173052, - 0.514487913, - 0.514472624, - 0.544061364, - 0.510800186, - 0.516727745, - 0.545580007, - 0.518474216, - 0.50413267, - 0.551257916 - ], - [ - 0.545500932, - 0.536815594, - 0.537811144, - 0.543658301, - 0.513137602, - 0.55071911, - 0.534395909, - 0.512947561, - 0.533737821, - 0.511725989, - 0.522091367, - 0.510747008, - 0.541552292, - 0.509787948, - 0.534709613, - 0.546341763, - 0.547648119, - 0.512014381, - 0.538390727, - 0.517935091, - 0.543038545, - 0.518090417, - 0.543156293, - 0.509084073, - 0.546276293, - 0.508983967, - 0.543493054, - 0.513399967, - 0.542150026, - 0.511184905, - 0.539540712, - 0.510109977, - 0.51362227, - 0.547711623, - 0.512129015, - 0.543632087, - 0.509569947, - 0.512387136, - 0.528815199, - 0.512614727 - ], - [ - 0.541113058, - 0.540174567, - 0.515131014, - 0.544201784, - 0.538403703, - 0.513926212, - 0.548774045, - 0.515024101, - 0.526468205, - 0.515302459, - 0.540009408, - 0.51008351, - 0.549617907, - 0.515847405, - 0.546236739, - 0.514784607, - 0.543987318, - 0.511918175, - 0.543546267, - 0.515257201, - 0.543035556, - 0.513497285, - 0.542170771, - 0.519056334, - 0.543202384, - 0.518200092, - 0.545814334, - 0.508619572, - 0.544846923, - 0.514478011, - 0.538244757, - 0.512253266, - 0.546109923, - 0.508796216, - 0.509887506, - 0.551741119, - 0.508426255, - 0.522894308, - 0.540235888, - 0.514232243 - ], - [ - 0.540429237, - 0.532267313, - 0.563953759, - 0.533135775, - 0.537187697, - 0.502501806, - 0.584493856, - 0.503271792, - 0.541670274, - 0.507923369, - 0.527474386, - 0.510362799, - 0.535386938, - 0.507340611, - 0.532201029, - 0.507470909, - 0.533873135, - 0.513496392, - 0.541262575, - 0.510170558, - 0.53032164, - 0.511474682, - 0.537774568, - 0.50702644, - 0.541070938, - 0.505826326, - 0.538034371, - 0.504136483, - 0.538581357, - 0.498086095, - 0.537771951, - 0.513426053, - 0.53713958, - 0.507413273, - 0.53254604, - 0.506096992, - 0.505653496, - 0.542114444, - 0.506942564, - 0.528423366 - ], - [ - 0.550761702, - 0.537608004, - 0.547377917, - 0.541577691, - 0.544505838, - 0.511617152, - 0.559819696, - 0.513957684, - 0.531832129, - 0.508567911, - 0.537651368, - 0.508371014, - 0.535497853, - 0.508324804, - 0.540513571, - 0.524649876, - 0.543841984, - 0.512234721, - 0.549649713, - 0.512772802, - 0.535396012, - 0.511622901, - 0.544970898, - 0.593475199, - 0.532039059, - 0.511000487, - 0.540654379, - 0.517257738, - 0.537510932, - 0.519001621, - 0.543566142, - 0.504613934, - 0.543507112, - 0.513335151, - 0.50996732, - 0.558996863, - 0.514996982, - 0.511867459, - 0.544968915, - 0.512645047 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "false", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.001452774805000001, - "scoreError" : 2.043892688722015E-4, - "scoreConfidence" : [ - 0.0012483855361277993, - 0.0016571640738722024 - ], - "scorePercentiles" : { - "0.0" : 7.39944E-4, - "50.0" : 0.001081594, - "90.0" : 0.0025082006, - "95.0" : 0.0029056797499999987, - "99.0" : 0.005877210500000007, - "99.9" : 0.006542498, - "99.99" : 0.006542498, - "99.999" : 0.006542498, - "99.9999" : 0.006542498, - "100.0" : 0.006542498 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.002325753, - 0.002148768, - 0.00222642, - 0.002402714, - 0.002554288, - 0.002350811, - 0.002424877, - 0.002175644, - 0.002212549, - 0.001432212, - 0.001272512, - 0.001149355, - 9.56564E-4, - 9.29823E-4, - 8.4162E-4, - 8.48508E-4, - 9.2725E-4, - 9.56209E-4, - 9.51742E-4, - 0.001110078, - 9.11499E-4, - 0.001039698, - 8.35568E-4, - 8.6715E-4, - 8.87111E-4, - 9.141E-4, - 9.25876E-4, - 0.001043432, - 0.003129829, - 0.001109829, - 0.001381683, - 0.001146525, - 0.001122438, - 0.001050784, - 0.001044408, - 0.001040494, - 0.001002906, - 0.00102025, - 9.97494E-4, - 9.78754E-4 - ], - [ - 0.00216955, - 0.002238055, - 0.002312813, - 0.002230858, - 0.002538276, - 0.002524893, - 0.00250996, - 0.005884121, - 0.001648282, - 0.001366098, - 0.001219532, - 0.001030975, - 0.001137594, - 0.001095699, - 0.001080546, - 9.60212E-4, - 0.001061132, - 0.001070872, - 9.13902E-4, - 9.35383E-4, - 9.70485E-4, - 0.001012828, - 0.001039893, - 0.001030872, - 0.001049682, - 0.001050779, - 0.001112775, - 0.004551147, - 0.001192754, - 0.001094033, - 0.001090691, - 0.001089763, - 0.001058105, - 0.001062676, - 0.00106577, - 0.0010743, - 0.001123074, - 0.001078641, - 0.001099878, - 0.001058111 - ], - [ - 0.002595838, - 0.002485733, - 0.002584858, - 0.002551415, - 0.002912322, - 0.003022016, - 0.002779477, - 0.002437209, - 0.002247075, - 0.001678548, - 0.001448135, - 0.001305884, - 0.001340869, - 0.001061612, - 8.58462E-4, - 8.48511E-4, - 8.49968E-4, - 9.09462E-4, - 9.08559E-4, - 9.33412E-4, - 8.93495E-4, - 0.001011949, - 9.27697E-4, - 0.001056219, - 0.001363957, - 0.001168449, - 9.44866E-4, - 9.32009E-4, - 0.003995803, - 0.001044425, - 0.001051146, - 0.001045116, - 0.001036892, - 0.001035933, - 0.001011313, - 0.00100706, - 0.001012978, - 0.001028277, - 0.001027684, - 0.001033081 - ], - [ - 0.002229089, - 0.002201015, - 0.002245934, - 0.002550233, - 0.002609295, - 0.002479579, - 0.002492366, - 0.006542498, - 0.0015473, - 0.001307647, - 0.001462406, - 0.001249024, - 0.001324179, - 0.001083345, - 0.001014775, - 0.001030695, - 0.001326463, - 0.001192666, - 0.001040857, - 9.50846E-4, - 9.7448E-4, - 0.001028869, - 0.001042478, - 0.001091321, - 0.001123473, - 0.001110919, - 0.001154131, - 0.003195902, - 0.001087463, - 0.001088005, - 0.00109049, - 0.001097794, - 0.001072443, - 0.001081313, - 0.001085792, - 0.001081875, - 0.001055446, - 0.001053745, - 0.001063538, - 0.001057736 - ], - [ - 0.002201075, - 0.002059575, - 0.00202336, - 0.002049919, - 0.002347074, - 0.00231592, - 0.002345761, - 0.002321082, - 0.005193071, - 0.00121674, - 0.001093692, - 0.001076008, - 0.001196052, - 0.001108412, - 0.001071015, - 0.001110918, - 0.001094322, - 0.00123574, - 0.001323898, - 9.98767E-4, - 7.39944E-4, - 8.31917E-4, - 8.06797E-4, - 7.9335E-4, - 8.44905E-4, - 8.01619E-4, - 7.70056E-4, - 0.002919469, - 9.69163E-4, - 8.37647E-4, - 8.70921E-4, - 9.215E-4, - 8.45886E-4, - 8.88968E-4, - 8.19774E-4, - 8.14486E-4, - 8.30794E-4, - 8.154E-4, - 8.34634E-4, - 8.27656E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "false", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.014660354005000003, - "scoreError" : 0.0015838184369991871, - "scoreConfidence" : [ - 0.013076535568000815, - 0.01624417244199919 - ], - "scorePercentiles" : { - "0.0" : 0.008228963, - "50.0" : 0.0111713995, - "90.0" : 0.025954685300000002, - "95.0" : 0.02844653005, - "99.0" : 0.0292994661, - "99.9" : 0.029441927, - "99.99" : 0.029441927, - "99.999" : 0.029441927, - "99.9999" : 0.029441927, - "100.0" : 0.029441927 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.013218883, - 0.013086975, - 0.024625946, - 0.023651571, - 0.013116302, - 0.011406264, - 0.013018283, - 0.011322048, - 0.011060793, - 0.013525084, - 0.023971512, - 0.026274982, - 0.02837758, - 0.012884288, - 0.010977808, - 0.011154813, - 0.011766028, - 0.011012162, - 0.010823216, - 0.010885942, - 0.011167606, - 0.010948347, - 0.011375489, - 0.010963104, - 0.012395139, - 0.020902731, - 0.025445173, - 0.024016264, - 0.0269101, - 0.029022972, - 0.029160282, - 0.019805869, - 0.011240293, - 0.01113251, - 0.011032191, - 0.011227953, - 0.011090581, - 0.011143439, - 0.011239424, - 0.01096265 - ], - [ - 0.013200622, - 0.011285075, - 0.02145133, - 0.021996235, - 0.011895178, - 0.010951813, - 0.013782903, - 0.011028706, - 0.011217598, - 0.013090832, - 0.026891805, - 0.029300872, - 0.028789962, - 0.012298945, - 0.011090837, - 0.011082606, - 0.011315008, - 0.01174827, - 0.010995589, - 0.011503324, - 0.011354038, - 0.010888163, - 0.010940985, - 0.01114347, - 0.011268328, - 0.020865942, - 0.025315578, - 0.027838332, - 0.028635796, - 0.028503231, - 0.027989483, - 0.018863994, - 0.011028464, - 0.011106872, - 0.010614385, - 0.010772215, - 0.010889433, - 0.011866702, - 0.011021784, - 0.011145494 - ], - [ - 0.012950312, - 0.012738677, - 0.020954729, - 0.020651578, - 0.010900639, - 0.011080281, - 0.01291853, - 0.011127862, - 0.010991205, - 0.012627023, - 0.02473321, - 0.027769156, - 0.029441927, - 0.012554991, - 0.011008685, - 0.010829972, - 0.011084247, - 0.010919663, - 0.011050175, - 0.012365025, - 0.011384157, - 0.010986744, - 0.011379858, - 0.011175193, - 0.010779074, - 0.020929097, - 0.02412412, - 0.025459008, - 0.028917435, - 0.028450159, - 0.028674973, - 0.020289596, - 0.012644774, - 0.011028658, - 0.010742485, - 0.011279617, - 0.01080469, - 0.010780223, - 0.012538273, - 0.010954387 - ], - [ - 0.009992416, - 0.008550945, - 0.019460498, - 0.016950785, - 0.008236984, - 0.009560541, - 0.010168171, - 0.008463956, - 0.009024128, - 0.010828827, - 0.023450024, - 0.025740929, - 0.024549479, - 0.010224351, - 0.008814202, - 0.008416728, - 0.009096058, - 0.008965569, - 0.008804806, - 0.008345704, - 0.008362356, - 0.008796883, - 0.008520282, - 0.008961309, - 0.008228963, - 0.019827029, - 0.025105035, - 0.025978436, - 0.025707771, - 0.026163991, - 0.026389409, - 0.01662712, - 0.009969251, - 0.010227208, - 0.009510767, - 0.009657822, - 0.008393212, - 0.008479312, - 0.009029666, - 0.00824399 - ], - [ - 0.010127973, - 0.008624524, - 0.022211979, - 0.020467341, - 0.009914756, - 0.009351593, - 0.010308551, - 0.0087002, - 0.008270381, - 0.012110299, - 0.021886775, - 0.024421184, - 0.024073688, - 0.009810047, - 0.009979216, - 0.008565235, - 0.008487332, - 0.008807312, - 0.010288064, - 0.008473148, - 0.008611679, - 0.008620008, - 0.008553207, - 0.008569453, - 0.008369827, - 0.018533389, - 0.022924128, - 0.025163656, - 0.025230833, - 0.024736509, - 0.025454948, - 0.017151, - 0.009445447, - 0.008464645, - 0.008520394, - 0.008250685, - 0.008299557, - 0.009063231, - 0.008625347, - 0.008445143 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "false", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.125223650845, - "scoreError" : 0.005492152075298723, - "scoreConfidence" : [ - 0.11973149876970128, - 0.13071580292029872 - ], - "scorePercentiles" : { - "0.0" : 0.114765186, - "50.0" : 0.118824614, - "90.0" : 0.1232881135, - "95.0" : 0.20478755019999978, - "99.0" : 0.22533022245000003, - "99.9" : 0.227194852, - "99.99" : 0.227194852, - "99.999" : 0.227194852, - "99.9999" : 0.227194852, - "100.0" : 0.227194852 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.207321738, - 0.179646243, - 0.118891575, - 0.120983369, - 0.117310468, - 0.119007987, - 0.227194852, - 0.116610986, - 0.115947501, - 0.11962009, - 0.117853741, - 0.11637451, - 0.119307773, - 0.118214055, - 0.117065213, - 0.117689843, - 0.116643742, - 0.11761892, - 0.118328222, - 0.116960449, - 0.116565295, - 0.118961754, - 0.116420448, - 0.116338128, - 0.117690273, - 0.118051104, - 0.119327444, - 0.117705745, - 0.117492397, - 0.115460036, - 0.11749915, - 0.119064629, - 0.115972996, - 0.118011525, - 0.116648746, - 0.118531357, - 0.116207464, - 0.131557975, - 0.118411455, - 0.11906897 - ], - [ - 0.206813735, - 0.178627773, - 0.116602546, - 0.121098512, - 0.118267913, - 0.117521926, - 0.223996143, - 0.115482734, - 0.116146648, - 0.118176421, - 0.116408739, - 0.116553763, - 0.120150541, - 0.118064069, - 0.117948519, - 0.117585546, - 0.116894165, - 0.117357565, - 0.118060416, - 0.117650215, - 0.11614703, - 0.118390773, - 0.11608505, - 0.115920244, - 0.115221061, - 0.117226908, - 0.119281036, - 0.11644224, - 0.117448441, - 0.11706415, - 0.117146016, - 0.118098051, - 0.116600399, - 0.11978806, - 0.116472216, - 0.116549365, - 0.117208052, - 0.119455651, - 0.117030292, - 0.118753693 - ], - [ - 0.210115904, - 0.181871316, - 0.120158983, - 0.124735803, - 0.121734646, - 0.12113649, - 0.221819206, - 0.118267548, - 0.117804164, - 0.121595285, - 0.119353141, - 0.118697961, - 0.1204855, - 0.119398954, - 0.119392217, - 0.119876593, - 0.11903241, - 0.119147896, - 0.12083391, - 0.118719421, - 0.118039698, - 0.120766122, - 0.119694092, - 0.119934548, - 0.118323514, - 0.117770657, - 0.120067705, - 0.119533771, - 0.120663792, - 0.119451774, - 0.120669025, - 0.122391766, - 0.121161582, - 0.122809495, - 0.119361675, - 0.120180357, - 0.119005137, - 0.121949897, - 0.119863181, - 0.120260225 - ], - [ - 0.205816979, - 0.183025108, - 0.117184449, - 0.121141169, - 0.117796476, - 0.118000717, - 0.2210331, - 0.115993072, - 0.118421332, - 0.120617544, - 0.121010879, - 0.117733144, - 0.118473208, - 0.117425258, - 0.116263095, - 0.117947462, - 0.116583497, - 0.115725517, - 0.116938146, - 0.116736114, - 0.117465758, - 0.119580026, - 0.116574515, - 0.116884043, - 0.116505885, - 0.114765186, - 0.118292644, - 0.115987436, - 0.117479018, - 0.116655297, - 0.119544942, - 0.119480841, - 0.116254589, - 0.11767135, - 0.116064358, - 0.117693036, - 0.116846289, - 0.117879489, - 0.117403405, - 0.118361865 - ], - [ - 0.210012685, - 0.185228403, - 0.120516877, - 0.122764358, - 0.11997701, - 0.120746981, - 0.225343698, - 0.120640798, - 0.120723427, - 0.121423894, - 0.12037527, - 0.11832139, - 0.122007242, - 0.119274639, - 0.117791972, - 0.120507591, - 0.120166317, - 0.120104447, - 0.120618855, - 0.119426057, - 0.119403096, - 0.121600397, - 0.119410783, - 0.119574858, - 0.119242405, - 0.118757653, - 0.121523783, - 0.119806878, - 0.120021124, - 0.119204175, - 0.120274462, - 0.123024454, - 0.119235578, - 0.120054578, - 0.118943897, - 0.123317409, - 0.120114857, - 0.133094216, - 0.124432495, - 0.121074776 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "Array", - "parallel" : "false", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 1.3466044483400004, - "scoreError" : 0.008458675050490869, - "scoreConfidence" : [ - 1.3381457732895095, - 1.3550631233904913 - ], - "scorePercentiles" : { - "0.0" : 1.297304071, - "50.0" : 1.3370579215, - "90.0" : 1.4030484235, - "95.0" : 1.4120806102, - "99.0" : 1.43038219308, - "99.9" : 1.44958506, - "99.99" : 1.44958506, - "99.999" : 1.44958506, - "99.9999" : 1.44958506, - "100.0" : 1.44958506 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.341811623, - 1.364712808, - 1.322721122, - 1.35025275, - 1.314173597, - 1.366215702, - 1.357136181, - 1.374694319, - 1.32597618, - 1.321977949, - 1.324921391, - 1.309207774, - 1.352492392, - 1.322805015, - 1.316393501, - 1.324262879, - 1.310277624, - 1.315630944, - 1.379775471, - 1.311146478, - 1.3275519, - 1.312408262, - 1.306817484, - 1.341305775, - 1.320381353, - 1.313695879, - 1.334813777, - 1.320291206, - 1.319546647, - 1.348633881, - 1.32261258, - 1.321116845, - 1.322202432, - 1.318610978, - 1.343728975, - 1.316399096, - 1.329779133, - 1.323976819, - 1.314090961, - 1.350240694 - ], - [ - 1.349513557, - 1.311865133, - 1.326224969, - 1.313759327, - 1.383548648, - 1.320076059, - 1.308051889, - 1.33280691, - 1.332378158, - 1.30693753, - 1.34272974, - 1.331034545, - 1.326386867, - 1.312233903, - 1.304453897, - 1.349440219, - 1.338737203, - 1.358742099, - 1.334919134, - 1.315657275, - 1.333155096, - 1.318131282, - 1.326760173, - 1.319802418, - 1.310454258, - 1.334898924, - 1.314402344, - 1.313870013, - 1.368111589, - 1.315444281, - 1.317246519, - 1.364648998, - 1.315293947, - 1.319855739, - 1.308460216, - 1.329712106, - 1.305473483, - 1.32658947, - 1.309173287, - 1.335083265 - ], - [ - 1.397831181, - 1.430396191, - 1.388717758, - 1.422651174, - 1.403428325, - 1.403348956, - 1.428174292, - 1.398674816, - 1.395069023, - 1.391029487, - 1.396995831, - 1.409127061, - 1.401693933, - 1.39379966, - 1.44958506, - 1.400716164, - 1.400781168, - 1.406054231, - 1.402844596, - 1.39904472, - 1.397121843, - 1.400352227, - 1.405526724, - 1.394545944, - 1.428996399, - 1.426939644, - 1.39926362, - 1.416527962, - 1.401032335, - 1.401288457, - 1.421360132, - 1.403175223, - 1.42294418, - 1.410030308, - 1.399298957, - 1.403071071, - 1.403526617, - 1.412137219, - 1.397477745, - 1.411005043 - ], - [ - 1.392542656, - 1.352359402, - 1.367400171, - 1.346164811, - 1.38428559, - 1.343271728, - 1.345939883, - 1.381196718, - 1.342227164, - 1.350750981, - 1.384704649, - 1.339537166, - 1.331402658, - 1.336178465, - 1.346433637, - 1.339954448, - 1.336935293, - 1.335814355, - 1.367974812, - 1.334125675, - 1.33718055, - 1.339690391, - 1.345981912, - 1.366209352, - 1.342401419, - 1.354873863, - 1.341401423, - 1.339753338, - 1.355761142, - 1.344676036, - 1.380838778, - 1.341318118, - 1.348037695, - 1.340981054, - 1.340141135, - 1.342969976, - 1.366712735, - 1.338844649, - 1.337374921, - 1.34523008 - ], - [ - 1.348477058, - 1.304449548, - 1.302742648, - 1.314850328, - 1.324812317, - 1.342555327, - 1.315531221, - 1.324917983, - 1.3400168, - 1.297304071, - 1.341496863, - 1.310135811, - 1.316467787, - 1.30623913, - 1.305945973, - 1.303800246, - 1.310917507, - 1.352638379, - 1.308740458, - 1.308616545, - 1.30374652, - 1.309423082, - 1.310346836, - 1.336610622, - 1.31597968, - 1.318347764, - 1.315796255, - 1.317824428, - 1.331216076, - 1.336758889, - 1.306620732, - 1.317268464, - 1.309535691, - 1.334100389, - 1.310849915, - 1.30618677, - 1.319966789, - 1.307793549, - 1.313171626, - 1.332670638 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "true", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.0016324048500000008, - "scoreError" : 1.6862513986738023E-4, - "scoreConfidence" : [ - 0.0014637797101326206, - 0.001801029989867381 - ], - "scorePercentiles" : { - "0.0" : 9.27776E-4, - "50.0" : 0.0015160665000000001, - "90.0" : 0.0020141216, - "95.0" : 0.002385646699999999, - "99.0" : 0.0055180590000000005, - "99.9" : 0.005906484, - "99.99" : 0.005906484, - "99.999" : 0.005906484, - "99.9999" : 0.005906484, - "100.0" : 0.005906484 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001940035, - 0.001957277, - 0.001870616, - 0.002014854, - 0.002143751, - 0.001972054, - 0.001996825, - 0.001958815, - 0.00184355, - 0.001801532, - 0.001623208, - 0.001625937, - 0.001572592, - 0.001660952, - 0.001595138, - 0.005906484, - 0.001717838, - 0.001606657, - 0.001441511, - 0.001380287, - 0.001321236, - 0.001082234, - 0.001017914, - 0.001040325, - 9.27776E-4, - 9.60866E-4, - 0.002479656, - 0.001110662, - 0.001033043, - 9.92849E-4, - 0.001007954, - 0.001180017, - 0.001132324, - 0.001034757, - 0.001089845, - 0.001002775, - 0.001050629, - 0.00113506, - 0.001104794, - 0.001004047 - ], - [ - 0.002305271, - 0.001934934, - 0.001904557, - 0.001932051, - 0.001888253, - 0.00174858, - 0.001939008, - 0.002030573, - 0.001980299, - 0.001950714, - 0.001810357, - 0.001897635, - 0.001813698, - 0.001575677, - 0.00156284, - 0.005505288, - 0.001487348, - 0.001385693, - 0.001543777, - 0.001518677, - 0.001560051, - 0.001454043, - 0.001439088, - 0.001426609, - 0.001527745, - 0.00165075, - 0.001661652, - 0.001589039, - 0.001545508, - 0.001520218, - 0.001532764, - 0.00142325, - 0.001392842, - 0.00140297, - 0.001452228, - 0.001446456, - 0.001478374, - 0.00162643, - 0.001387612, - 0.00127332 - ], - [ - 0.002389877, - 0.001880005, - 0.001825932, - 0.001777342, - 0.00185394, - 0.001649759, - 0.0016418, - 0.001805565, - 0.00200753, - 0.001746883, - 0.001871401, - 0.001634356, - 0.001639973, - 0.001714845, - 0.001567931, - 0.005249702, - 0.001639867, - 0.001527175, - 0.001410217, - 0.001448725, - 0.001426385, - 0.001316335, - 0.001355841, - 0.001256098, - 0.001318368, - 0.001438122, - 0.001512049, - 0.001420639, - 0.001286284, - 0.001380407, - 0.001397048, - 0.001513456, - 0.001381087, - 0.001467978, - 0.001489544, - 0.00143748, - 0.001453053, - 0.001414018, - 0.001279875, - 0.001322264 - ], - [ - 0.002214616, - 0.00184027, - 0.00193746, - 0.001942361, - 0.001954314, - 0.002479814, - 0.002055242, - 0.001986684, - 0.002220009, - 0.001687158, - 0.001536173, - 0.001540815, - 0.001643298, - 0.002499528, - 0.001727221, - 0.005518188, - 0.001551442, - 0.001465505, - 0.001509311, - 0.001429083, - 0.001373905, - 0.001401124, - 0.001576808, - 0.001356261, - 0.001701732, - 0.001581883, - 0.001757345, - 0.001594522, - 0.001424595, - 0.001403575, - 0.001317265, - 0.001349201, - 0.001292779, - 0.001264693, - 0.001307673, - 0.001335701, - 0.001320933, - 0.001252316, - 0.001274964, - 0.001237462 - ], - [ - 0.002390691, - 0.002160216, - 0.001968966, - 0.001960705, - 0.001982437, - 0.002055081, - 0.002184325, - 0.001997472, - 0.001940201, - 0.00180035, - 0.00185912, - 0.001658738, - 0.0017004, - 0.001418208, - 0.001401416, - 0.005280414, - 0.001164304, - 0.001031478, - 0.001205233, - 0.00128658, - 0.001236161, - 0.001162103, - 0.001108272, - 0.001105022, - 0.001032385, - 0.001077308, - 0.00108411, - 0.00107432, - 0.001130736, - 0.001054078, - 0.001097306, - 0.001076641, - 9.63444E-4, - 0.001036766, - 0.001040354, - 0.001031146, - 9.51769E-4, - 9.31526E-4, - 0.001012125, - 9.71823E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "true", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.008577721689999998, - "scoreError" : 6.277424315498137E-4, - "scoreConfidence" : [ - 0.007949979258450184, - 0.009205464121549812 - ], - "scorePercentiles" : { - "0.0" : 0.00528341, - "50.0" : 0.0080757815, - "90.0" : 0.012349076200000001, - "95.0" : 0.014107499649999992, - "99.0" : 0.01599074553, - "99.9" : 0.016369793, - "99.99" : 0.016369793, - "99.999" : 0.016369793, - "99.9999" : 0.016369793, - "100.0" : 0.016369793 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.015289456, - 0.011907576, - 0.013008206, - 0.015761415, - 0.009451532, - 0.010212174, - 0.00806612, - 0.009310383, - 0.008869385, - 0.008085443, - 0.007979568, - 0.008324332, - 0.010283702, - 0.009641955, - 0.009380253, - 0.008939809, - 0.008930072, - 0.012629152, - 0.00747356, - 0.008667016, - 0.009214786, - 0.007855497, - 0.008140933, - 0.007924001, - 0.008190619, - 0.008683682, - 0.007164312, - 0.010209601, - 0.006068133, - 0.005602633, - 0.006519417, - 0.006291791, - 0.005872884, - 0.005874662, - 0.006041558, - 0.005840517, - 0.005794749, - 0.006104418, - 0.006099446, - 0.007236192 - ], - [ - 0.00952951, - 0.009841199, - 0.012145022, - 0.012866488, - 0.008386363, - 0.008322697, - 0.008964617, - 0.008095014, - 0.011305205, - 0.006560136, - 0.007220596, - 0.008633089, - 0.008001919, - 0.010211929, - 0.012016962, - 0.013199869, - 0.011080392, - 0.013516479, - 0.010233496, - 0.006937262, - 0.006272227, - 0.00586405, - 0.007660086, - 0.005940835, - 0.006025189, - 0.005659474, - 0.005918475, - 0.006960344, - 0.01009088, - 0.005595636, - 0.006020262, - 0.005644815, - 0.005842173, - 0.006136733, - 0.006036838, - 0.005816437, - 0.005864726, - 0.005856194, - 0.006202152, - 0.008154612 - ], - [ - 0.015505641, - 0.014883351, - 0.012335677, - 0.015677889, - 0.007385323, - 0.007052293, - 0.007554823, - 0.007295784, - 0.011670811, - 0.006936226, - 0.006289619, - 0.006600229, - 0.006661069, - 0.007371294, - 0.00789171, - 0.010963719, - 0.008393633, - 0.00900093, - 0.009956215, - 0.006580165, - 0.006706139, - 0.005905724, - 0.006004231, - 0.006456601, - 0.005820557, - 0.006153382, - 0.00627023, - 0.006505954, - 0.01016811, - 0.00679749, - 0.006724039, - 0.006246371, - 0.010792968, - 0.007705646, - 0.00629471, - 0.00573758, - 0.006292784, - 0.00642003, - 0.007833918, - 0.006924664 - ], - [ - 0.011936085, - 0.013283098, - 0.012401681, - 0.012153149, - 0.009877553, - 0.009133873, - 0.008525926, - 0.00864012, - 0.009545584, - 0.009847231, - 0.010250936, - 0.010083929, - 0.011242957, - 0.01110607, - 0.012350565, - 0.014163148, - 0.011846958, - 0.016369793, - 0.011385426, - 0.010413653, - 0.007200527, - 0.007396477, - 0.008366155, - 0.010825744, - 0.008664062, - 0.008294155, - 0.008149035, - 0.014565591, - 0.008995959, - 0.009875978, - 0.010588592, - 0.009759168, - 0.009456366, - 0.011963493, - 0.007282042, - 0.00794557, - 0.006949164, - 0.00564328, - 0.007023282, - 0.008020076 - ], - [ - 0.01228792, - 0.014138606, - 0.013098493, - 0.015993062, - 0.011191266, - 0.010850908, - 0.010566442, - 0.006914748, - 0.012644713, - 0.010939991, - 0.009202505, - 0.010092527, - 0.010455613, - 0.010771383, - 0.009618907, - 0.008769713, - 0.008498146, - 0.007167563, - 0.005350863, - 0.005389168, - 0.006858696, - 0.005347486, - 0.005524679, - 0.005817592, - 0.00584043, - 0.005988361, - 0.006512606, - 0.005695742, - 0.00907148, - 0.00528341, - 0.005568608, - 0.005668378, - 0.005585902, - 0.005448298, - 0.005462288, - 0.005664285, - 0.005466468, - 0.005341627, - 0.006496873, - 0.00609729 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "true", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.07119095882999998, - "scoreError" : 0.0029088012720277765, - "scoreConfidence" : [ - 0.0682821575579722, - 0.07409976010202776 - ], - "scorePercentiles" : { - "0.0" : 0.057938179, - "50.0" : 0.0662982395, - "90.0" : 0.0914451824, - "95.0" : 0.09869718915, - "99.0" : 0.10994574531000002, - "99.9" : 0.109992024, - "99.99" : 0.109992024, - "99.999" : 0.109992024, - "99.9999" : 0.109992024, - "100.0" : 0.109992024 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.098697876, - 0.061926468, - 0.061250007, - 0.088623655, - 0.061220909, - 0.064032315, - 0.072421285, - 0.096251758, - 0.060907533, - 0.063049034, - 0.061561174, - 0.062241904, - 0.085187881, - 0.06072843, - 0.063179866, - 0.062123759, - 0.061613672, - 0.089586408, - 0.061756347, - 0.062142447, - 0.062223311, - 0.062080558, - 0.062371892, - 0.086214674, - 0.062058788, - 0.061878102, - 0.062193621, - 0.062032502, - 0.063296114, - 0.088037571, - 0.062621277, - 0.062448013, - 0.0624522, - 0.064893418, - 0.085174047, - 0.0623095, - 0.062823606, - 0.06370958, - 0.064189725, - 0.062591892 - ], - [ - 0.100038737, - 0.063057661, - 0.06236334, - 0.063279825, - 0.063625863, - 0.067916447, - 0.07999779, - 0.098117475, - 0.062444392, - 0.063493396, - 0.062953585, - 0.062928624, - 0.062249394, - 0.061927839, - 0.062579708, - 0.062532957, - 0.064150939, - 0.097614639, - 0.062142473, - 0.062591781, - 0.063544037, - 0.062180153, - 0.063468597, - 0.062222739, - 0.063026036, - 0.062286874, - 0.062608118, - 0.063710344, - 0.082311149, - 0.063825188, - 0.062547022, - 0.06272162, - 0.06315118, - 0.063461659, - 0.086158388, - 0.063921157, - 0.064143988, - 0.067996625, - 0.065209839, - 0.084824915 - ], - [ - 0.099394188, - 0.059529625, - 0.059176878, - 0.058163223, - 0.058088005, - 0.065361215, - 0.077455381, - 0.098443878, - 0.05816944, - 0.057938179, - 0.059003168, - 0.08163011, - 0.059364573, - 0.05919338, - 0.059883568, - 0.059750754, - 0.064676004, - 0.09290278, - 0.059294575, - 0.060902141, - 0.058588614, - 0.058882129, - 0.082029072, - 0.059474764, - 0.058923817, - 0.060581371, - 0.061238158, - 0.060313502, - 0.0868189, - 0.061612464, - 0.060746497, - 0.061029595, - 0.060716643, - 0.061596077, - 0.061353586, - 0.061834313, - 0.060806843, - 0.061338826, - 0.064673093, - 0.086663602 - ], - [ - 0.109959571, - 0.077361252, - 0.074537262, - 0.098737329, - 0.074412733, - 0.078277569, - 0.088062989, - 0.109992024, - 0.075346459, - 0.074996766, - 0.074395366, - 0.074083366, - 0.074108317, - 0.074075923, - 0.074435092, - 0.075878556, - 0.07565999, - 0.108577002, - 0.074760851, - 0.076100649, - 0.074610203, - 0.07499767, - 0.074492861, - 0.100008804, - 0.074631297, - 0.074812077, - 0.075059403, - 0.074644412, - 0.09638166, - 0.074329408, - 0.074879403, - 0.077468982, - 0.074062351, - 0.074538564, - 0.10227499, - 0.074572022, - 0.074792635, - 0.074302235, - 0.07569051, - 0.093709664 - ], - [ - 0.102557128, - 0.065995882, - 0.066921165, - 0.065413884, - 0.066464858, - 0.071398865, - 0.077841863, - 0.098684139, - 0.065997759, - 0.065785726, - 0.066510141, - 0.084956572, - 0.066695909, - 0.067435329, - 0.066131621, - 0.066045729, - 0.071904295, - 0.093863044, - 0.067571842, - 0.066585959, - 0.067867338, - 0.066858902, - 0.090547067, - 0.067149227, - 0.067030312, - 0.067853062, - 0.067213213, - 0.067833678, - 0.091544973, - 0.069103765, - 0.06910723, - 0.069064692, - 0.069005708, - 0.088409685, - 0.06875371, - 0.072335076, - 0.069090322, - 0.070214845, - 0.069114463, - 0.090342028 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "true", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 2.0319950418649997, - "scoreError" : 0.5211620802047312, - "scoreConfidence" : [ - 1.5108329616602685, - 2.553157122069731 - ], - "scorePercentiles" : { - "0.0" : 0.569006906, - "50.0" : 0.779725698, - "90.0" : 5.940439726199999, - "95.0" : 5.9875035773, - "99.0" : 6.285061951010001, - "99.9" : 6.337889527, - "99.99" : 6.337889527, - "99.999" : 6.337889527, - "99.9999" : 6.337889527, - "100.0" : 6.337889527 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.732891377, - 5.901162347, - 0.714113801, - 6.18111116, - 0.627989714, - 0.752672885, - 6.337889527, - 0.608036256, - 0.737122927, - 6.286111959, - 0.625014468, - 0.742711287, - 6.070971124, - 0.602514403, - 0.732305347, - 0.873132214, - 0.727112731, - 6.081064376, - 0.699252495, - 0.745478523, - 1.035162257, - 0.621923723, - 6.064674076, - 0.713692333, - 0.617275355, - 0.7145615, - 1.071945367, - 0.659489727, - 5.775745437, - 0.744170559, - 0.717122209, - 0.733559549, - 1.092823686, - 0.902232064, - 0.789528093, - 6.122942594, - 0.620116326, - 0.795400931, - 0.87504792, - 0.654644518 - ], - [ - 5.952647173, - 0.682681643, - 5.677702479, - 0.717335844, - 5.94005586, - 0.717991597, - 5.895217926, - 0.721281044, - 1.062980422, - 0.732305723, - 0.715388049, - 5.899226508, - 0.733868262, - 0.607752292, - 0.720464459, - 1.107466208, - 5.961118, - 0.72882123, - 0.8181884, - 0.899255073, - 5.784416039, - 0.696069404, - 0.927750879, - 0.655095691, - 0.712641921, - 1.064728246, - 5.756822699, - 0.711580735, - 0.784196356, - 0.753945518, - 0.625338009, - 5.684295386, - 1.072434004, - 0.748906113, - 0.695537524, - 0.921829778, - 0.760114438, - 5.890186456, - 0.586342193, - 0.761128958 - ], - [ - 5.981371676, - 0.78471786, - 5.758662083, - 0.784026924, - 6.055241164, - 0.7801473, - 0.732848462, - 5.808412343, - 1.132068931, - 0.750103891, - 0.776475034, - 5.952329689, - 0.920741837, - 0.725519688, - 0.775654961, - 5.784556704, - 0.745876065, - 0.686177319, - 0.795501454, - 1.131179653, - 0.904428742, - 5.986004122, - 0.810831571, - 0.709497773, - 0.74604684, - 1.063352189, - 0.769322513, - 5.551257118, - 0.757117286, - 0.749196159, - 0.723959417, - 0.775457368, - 1.087986379, - 5.884781759, - 0.698932946, - 0.753435628, - 0.949096738, - 0.683875219, - 0.779699251, - 5.968177193 - ], - [ - 5.907471101, - 0.744300403, - 5.929336369, - 0.785939744, - 5.871885435, - 0.745849809, - 5.702665491, - 0.775897137, - 0.746619393, - 5.628070853, - 0.932096321, - 0.809273542, - 0.739665211, - 5.941330897, - 0.754068207, - 0.81103398, - 0.952667588, - 5.947631321, - 0.779752145, - 0.758446759, - 0.988159688, - 0.766493319, - 5.610001951, - 0.849616408, - 0.738984942, - 0.626318772, - 0.767349394, - 5.743795817, - 0.753512025, - 0.694002214, - 0.770938498, - 0.872938117, - 5.987582496, - 0.747803617, - 0.779431284, - 0.933870202, - 0.780027763, - 0.851126924, - 0.774392183, - 0.925415261 - ], - [ - 5.936553319, - 0.569006906, - 5.61187143, - 0.72124442, - 5.794094312, - 0.717332644, - 0.893320103, - 5.716889699, - 0.675926696, - 0.936897195, - 6.001085677, - 0.875753799, - 0.732516633, - 0.763952322, - 5.690245913, - 0.96053246, - 0.775321631, - 0.72087086, - 0.741399185, - 5.782591203, - 0.784603921, - 0.611199523, - 0.76188809, - 0.637178646, - 5.966135651, - 0.598805249, - 0.772706149, - 0.855951024, - 0.772859385, - 5.940482378, - 0.867278366, - 0.718769649, - 0.75566602, - 0.73468337, - 0.856214164, - 0.784967123, - 5.856097283, - 0.708790961, - 0.619489899, - 0.752177601 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "false", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.00144411897, - "scoreError" : 1.4413450788996015E-4, - "scoreConfidence" : [ - 0.0012999844621100398, - 0.00158825347788996 - ], - "scorePercentiles" : { - "0.0" : 8.05575E-4, - "50.0" : 0.0013706985, - "90.0" : 0.0018674752, - "95.0" : 0.0020281819499999992, - "99.0" : 0.004851426370000002, - "99.9" : 0.005166507, - "99.99" : 0.005166507, - "99.999" : 0.005166507, - "99.9999" : 0.005166507, - "100.0" : 0.005166507 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001690476, - 0.001698545, - 0.001701383, - 0.001742859, - 0.001866856, - 0.001704302, - 0.001685093, - 0.001710198, - 0.001804078, - 0.001760309, - 0.001942196, - 0.001952496, - 0.001675649, - 0.001738436, - 0.001682695, - 0.001683554, - 0.001661547, - 0.001462174, - 0.001951928, - 0.001493878, - 0.001439094, - 0.001153695, - 0.001131195, - 0.001050307, - 0.001108278, - 0.001076039, - 0.001352196, - 0.001302706, - 0.001076109, - 0.001109246, - 0.00107544, - 0.001164931, - 0.001091231, - 0.001078868, - 9.8917E-4, - 9.70606E-4, - 9.62847E-4, - 9.54692E-4, - 9.52485E-4, - 9.25712E-4 - ], - [ - 0.001757569, - 0.001778064, - 0.001729638, - 0.001729109, - 0.001784379, - 0.002187767, - 0.001793603, - 0.001882558, - 0.001781801, - 0.001819623, - 0.001721747, - 0.001867544, - 0.002451934, - 0.001842353, - 0.00196455, - 0.001562914, - 0.001453033, - 0.001511741, - 0.001599143, - 0.001559936, - 0.00161875, - 0.005166507, - 0.001395782, - 0.001169325, - 0.001246432, - 0.001168466, - 0.001186497, - 0.001112094, - 0.001160037, - 9.7974E-4, - 0.001031147, - 0.001009271, - 9.65466E-4, - 9.48101E-4, - 9.62813E-4, - 9.42769E-4, - 9.61569E-4, - 9.47078E-4, - 8.94699E-4, - 8.7236E-4 - ], - [ - 0.001687143, - 0.001694359, - 0.001679916, - 0.002031531, - 0.001807471, - 0.001738398, - 0.001732838, - 0.001838139, - 0.00180819, - 0.001874126, - 0.001876524, - 0.001872413, - 0.001704608, - 0.001864665, - 0.001695828, - 0.001573316, - 0.001353619, - 0.001785185, - 0.00141749, - 0.001315806, - 0.001276864, - 0.004353898, - 0.001115672, - 9.60005E-4, - 0.001002437, - 9.09894E-4, - 0.001256622, - 9.13618E-4, - 0.001145834, - 8.89234E-4, - 9.36421E-4, - 9.81714E-4, - 0.001060234, - 9.6024E-4, - 9.70117E-4, - 9.68868E-4, - 9.39992E-4, - 9.39557E-4, - 9.36362E-4, - 9.34212E-4 - ], - [ - 0.001685313, - 0.001793676, - 0.001689126, - 0.001735247, - 0.001705564, - 0.001652419, - 0.001661137, - 0.001917616, - 0.001701093, - 0.001750989, - 0.001774309, - 0.001622198, - 0.0016295, - 0.001611113, - 0.001676974, - 0.00183387, - 0.001507664, - 0.001324923, - 0.001387778, - 0.001241533, - 0.001207033, - 0.00485386, - 0.001087973, - 9.04675E-4, - 8.66082E-4, - 8.24736E-4, - 8.88663E-4, - 9.31625E-4, - 9.12122E-4, - 9.39324E-4, - 9.42221E-4, - 0.001099787, - 9.41413E-4, - 0.001069935, - 9.868E-4, - 9.42417E-4, - 9.3856E-4, - 9.45171E-4, - 9.40913E-4, - 9.359E-4 - ], - [ - 0.001823102, - 0.001703637, - 0.001749733, - 0.001726901, - 0.002044767, - 0.001711828, - 0.001735959, - 0.001858417, - 0.001756085, - 0.001849844, - 0.002089564, - 0.001689193, - 0.001716641, - 0.002076595, - 0.001458872, - 0.001393614, - 0.001334812, - 0.001317154, - 0.001654236, - 0.00129221, - 0.001265566, - 0.004610497, - 0.001200338, - 8.05575E-4, - 9.00256E-4, - 8.08609E-4, - 8.94393E-4, - 9.82426E-4, - 9.83949E-4, - 8.54709E-4, - 8.65451E-4, - 9.48713E-4, - 9.31518E-4, - 9.57578E-4, - 0.001028112, - 9.68538E-4, - 9.68434E-4, - 9.70016E-4, - 9.52997E-4, - 9.86935E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "false", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.013206583380000001, - "scoreError" : 6.965410895018386E-4, - "scoreConfidence" : [ - 0.012510042290498163, - 0.01390312446950184 - ], - "scorePercentiles" : { - "0.0" : 0.010442656, - "50.0" : 0.0113289795, - "90.0" : 0.0172247283, - "95.0" : 0.018881933699999996, - "99.0" : 0.0212418549, - "99.9" : 0.023316947, - "99.99" : 0.023316947, - "99.999" : 0.023316947, - "99.9999" : 0.023316947, - "100.0" : 0.023316947 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.011319397, - 0.01094127, - 0.010828579, - 0.016755952, - 0.017207253, - 0.018475886, - 0.010958122, - 0.010837759, - 0.011161174, - 0.010848312, - 0.010799365, - 0.013667912, - 0.010834667, - 0.01086026, - 0.01089114, - 0.010655912, - 0.011780302, - 0.010849074, - 0.015698087, - 0.016776034, - 0.016424597, - 0.016789752, - 0.016679536, - 0.016508272, - 0.01207093, - 0.010790917, - 0.01117041, - 0.010920946, - 0.010673105, - 0.010701652, - 0.010814818, - 0.010914778, - 0.010829237, - 0.010898062, - 0.011514016, - 0.011476507, - 0.013597259, - 0.011102703, - 0.010924414, - 0.010728184 - ], - [ - 0.010989356, - 0.01083752, - 0.013219814, - 0.010887273, - 0.010812915, - 0.013685654, - 0.010703595, - 0.011881528, - 0.010841942, - 0.014489386, - 0.016861992, - 0.0198898, - 0.010660166, - 0.010976585, - 0.010677767, - 0.010796232, - 0.011542504, - 0.010882592, - 0.010771367, - 0.011171346, - 0.010858665, - 0.010971185, - 0.011003825, - 0.010940809, - 0.013328435, - 0.016833844, - 0.016986694, - 0.01648048, - 0.017107607, - 0.016526824, - 0.014991759, - 0.010714233, - 0.010639631, - 0.010640616, - 0.010442656, - 0.011612415, - 0.010739526, - 0.010747854, - 0.01100877, - 0.010776813 - ], - [ - 0.015067462, - 0.014540896, - 0.017769164, - 0.014535313, - 0.014533189, - 0.017420671, - 0.014552515, - 0.014796533, - 0.015193315, - 0.018330914, - 0.020867073, - 0.023316947, - 0.014524133, - 0.014611586, - 0.014601999, - 0.015226382, - 0.014583233, - 0.014917669, - 0.014720144, - 0.014450363, - 0.014571246, - 0.01519772, - 0.014442029, - 0.014923061, - 0.017523711, - 0.020658616, - 0.021232737, - 0.020525653, - 0.021241947, - 0.020938064, - 0.018511257, - 0.015012936, - 0.014574831, - 0.015124672, - 0.014513308, - 0.015074555, - 0.014634032, - 0.014422447, - 0.0146051, - 0.014664788 - ], - [ - 0.012199326, - 0.01234182, - 0.013368158, - 0.010912839, - 0.010938774, - 0.013559087, - 0.01068906, - 0.011452764, - 0.01072447, - 0.014858919, - 0.017428682, - 0.019607399, - 0.010653402, - 0.010839054, - 0.010691784, - 0.010848783, - 0.011132915, - 0.011019152, - 0.010750384, - 0.011096056, - 0.010915404, - 0.010704489, - 0.010691958, - 0.010887236, - 0.013718594, - 0.016655682, - 0.01747899, - 0.016464469, - 0.017125122, - 0.016738548, - 0.014588258, - 0.010765148, - 0.010673151, - 0.010883638, - 0.010663827, - 0.011754636, - 0.011019821, - 0.010913406, - 0.010819426, - 0.010814163 - ], - [ - 0.010683265, - 0.011351579, - 0.013511056, - 0.011124805, - 0.010951311, - 0.013750106, - 0.0108392, - 0.010966176, - 0.010694022, - 0.014688158, - 0.017030034, - 0.018901443, - 0.011070214, - 0.010988728, - 0.010706448, - 0.011125562, - 0.010669985, - 0.010814155, - 0.010740054, - 0.010839326, - 0.011338562, - 0.010686574, - 0.01072704, - 0.011092215, - 0.013692488, - 0.01722667, - 0.016858808, - 0.016891896, - 0.016848299, - 0.017391685, - 0.014943125, - 0.011186574, - 0.01077468, - 0.011161915, - 0.010697254, - 0.011247906, - 0.010795708, - 0.010867812, - 0.010749516, - 0.01074279 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "false", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.13730924924500004, - "scoreError" : 0.005118955818106803, - "scoreConfidence" : [ - 0.13219029342689323, - 0.14242820506310686 - ], - "scorePercentiles" : { - "0.0" : 0.115529836, - "50.0" : 0.132974545, - "90.0" : 0.169567189, - "95.0" : 0.17364531219999998, - "99.0" : 0.20323564262000002, - "99.9" : 0.207845365, - "99.99" : 0.207845365, - "99.999" : 0.207845365, - "99.9999" : 0.207845365, - "100.0" : 0.207845365 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.125709801, - 0.169582016, - 0.118280634, - 0.118805392, - 0.136134828, - 0.117492135, - 0.120807179, - 0.145796697, - 0.170759461, - 0.171942683, - 0.119458628, - 0.118263103, - 0.119138683, - 0.119466062, - 0.119325243, - 0.13570329, - 0.118950515, - 0.11741345, - 0.119440832, - 0.119668918, - 0.121803115, - 0.173728765, - 0.118296221, - 0.118741815, - 0.11810111, - 0.118429135, - 0.119513438, - 0.119277429, - 0.132511016, - 0.119371079, - 0.118863042, - 0.119311121, - 0.119459506, - 0.118979439, - 0.116992552, - 0.13293585, - 0.118703476, - 0.118151209, - 0.119859186, - 0.118485443 - ], - [ - 0.122708509, - 0.169724459, - 0.122343625, - 0.120143458, - 0.133944618, - 0.118596479, - 0.117543409, - 0.138584029, - 0.179878952, - 0.171679407, - 0.117352394, - 0.117426129, - 0.117859319, - 0.11801009, - 0.118500342, - 0.132641032, - 0.118149333, - 0.117557628, - 0.116301345, - 0.118046284, - 0.126346292, - 0.17036254, - 0.117077979, - 0.115529836, - 0.117312432, - 0.116686175, - 0.117537517, - 0.11661324, - 0.132428721, - 0.115931203, - 0.116975293, - 0.117101372, - 0.117184583, - 0.1179354, - 0.119883692, - 0.132895517, - 0.118068025, - 0.117734404, - 0.117751452, - 0.118900878 - ], - [ - 0.153442373, - 0.201003126, - 0.147053184, - 0.148632986, - 0.163173451, - 0.147429076, - 0.148078888, - 0.170019301, - 0.203253224, - 0.201495086, - 0.147006137, - 0.147586198, - 0.146363686, - 0.147576959, - 0.148650191, - 0.164126034, - 0.14651584, - 0.14821729, - 0.149311918, - 0.148199142, - 0.150696367, - 0.207845365, - 0.149449298, - 0.148999539, - 0.1483306, - 0.145778275, - 0.148355275, - 0.148250576, - 0.164044111, - 0.146833573, - 0.149255934, - 0.148158711, - 0.14835112, - 0.148913229, - 0.147508632, - 0.162191723, - 0.148551753, - 0.147310226, - 0.148428472, - 0.146969906 - ], - [ - 0.15193948, - 0.198805746, - 0.149503659, - 0.146625777, - 0.159659882, - 0.145688301, - 0.146261942, - 0.168417183, - 0.199572114, - 0.200445624, - 0.146695244, - 0.143996946, - 0.144820739, - 0.143896789, - 0.146042857, - 0.160027611, - 0.145726959, - 0.146192802, - 0.14565085, - 0.143566844, - 0.144956713, - 0.198005191, - 0.145694733, - 0.146239453, - 0.144691253, - 0.144509853, - 0.145680006, - 0.143381273, - 0.161538544, - 0.146784214, - 0.145244601, - 0.14574858, - 0.143877456, - 0.144851392, - 0.146264006, - 0.160217672, - 0.14810679, - 0.146166865, - 0.14462749, - 0.145616778 - ], - [ - 0.127484549, - 0.169433746, - 0.117384433, - 0.118108658, - 0.13301324, - 0.117829761, - 0.118870298, - 0.139930169, - 0.170188287, - 0.172059709, - 0.118165349, - 0.118143728, - 0.116508821, - 0.116350517, - 0.118645654, - 0.134135036, - 0.118059286, - 0.117665641, - 0.11725654, - 0.11699474, - 0.118708764, - 0.169690569, - 0.120234526, - 0.118921215, - 0.117702115, - 0.11711942, - 0.117686057, - 0.117988653, - 0.132390966, - 0.117542988, - 0.118343379, - 0.117966833, - 0.116747975, - 0.116303794, - 0.118614054, - 0.131931844, - 0.118186202, - 0.115929974, - 0.11788255, - 0.117731933 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "ArrayBuffer", - "parallel" : "false", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 1.5613428742049995, - "scoreError" : 0.029697804438330113, - "scoreConfidence" : [ - 1.5316450697666695, - 1.5910406786433295 - ], - "scorePercentiles" : { - "0.0" : 1.265329954, - "50.0" : 1.5200654789999999, - "90.0" : 1.7472271115, - "95.0" : 1.77241855155, - "99.0" : 1.92966102168, - "99.9" : 2.133928437, - "99.99" : 2.133928437, - "99.999" : 2.133928437, - "99.9999" : 2.133928437, - "100.0" : 2.133928437 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 1.594984481, - 1.496853897, - 1.473899031, - 1.461776634, - 1.507860966, - 1.478080964, - 1.497753494, - 1.467306964, - 1.493420408, - 1.469991615, - 1.57987159, - 1.508988271, - 1.469735999, - 1.490375058, - 1.469273169, - 1.484540966, - 1.488299711, - 1.472959536, - 1.495343281, - 1.350935954, - 1.47764845, - 1.495673411, - 1.458356124, - 1.486492554, - 1.49275478, - 1.481819948, - 1.343654247, - 1.474646952, - 1.477264547, - 1.486225477, - 1.496908346, - 1.484973166, - 1.345389108, - 1.463544258, - 1.484206822, - 1.484803911, - 1.46451219, - 1.501671727, - 1.467194023, - 1.504939934 - ], - [ - 1.528393578, - 1.542066646, - 1.525392792, - 1.521268304, - 1.545328811, - 1.538655806, - 1.554117621, - 1.494340248, - 1.468602386, - 1.499913203, - 1.472307946, - 1.489940333, - 1.500451164, - 1.4811337, - 1.502707082, - 1.492123202, - 1.495936557, - 1.548646968, - 1.538460921, - 1.540159689, - 1.529328589, - 1.484618785, - 1.506720469, - 1.48811634, - 1.486253252, - 1.472760167, - 1.618323177, - 1.480361471, - 1.469255489, - 1.471503888, - 1.488758195, - 1.354481097, - 1.479983903, - 1.486095688, - 1.357488659, - 1.47032122, - 1.489277769, - 1.466733642, - 1.491127033, - 1.496722818 - ], - [ - 1.898823975, - 1.768234116, - 1.746842852, - 1.736707339, - 1.717203994, - 1.890019242, - 1.764742318, - 1.741231345, - 1.760065832, - 1.740381888, - 1.747269807, - 1.772638785, - 1.917211646, - 2.133928437, - 1.929712567, - 1.815156888, - 1.924558035, - 1.775150541, - 1.744102949, - 1.727449377, - 1.766270604, - 1.734579058, - 1.77399411, - 1.738710058, - 1.738096187, - 1.740924815, - 1.747601231, - 1.72745084, - 1.746198783, - 1.758098523, - 1.733622628, - 1.74616799, - 1.75481693, - 1.745187034, - 1.602320483, - 1.728677449, - 1.754043255, - 1.746519279, - 1.750337614, - 1.595451019 - ], - [ - 1.497370654, - 1.49345297, - 1.479703092, - 1.486967705, - 1.613509007, - 1.620095949, - 1.502128379, - 1.479070756, - 1.462885942, - 1.494943703, - 1.476596238, - 1.589592982, - 1.520069206, - 1.475149384, - 1.491473808, - 1.464458634, - 1.495713695, - 1.265329954, - 1.619136971, - 1.601664887, - 1.498614161, - 1.484845773, - 1.469651376, - 1.50219999, - 1.483394518, - 1.428980325, - 1.497043147, - 1.480697313, - 1.468889947, - 1.507768465, - 1.479657944, - 1.45251882, - 1.520061752, - 1.483623727, - 1.478593841, - 1.642746938, - 1.529329623, - 1.464187324, - 1.500516307, - 1.466833218 - ], - [ - 1.574385377, - 1.572842981, - 1.557225966, - 1.663354034, - 1.566039638, - 1.58603431, - 1.558167112, - 1.576431365, - 1.565695295, - 1.576743659, - 1.549468578, - 1.571817548, - 1.541265582, - 1.565611732, - 1.581081085, - 1.543428542, - 1.547138696, - 1.554976201, - 1.576081816, - 1.349471647, - 1.578644233, - 1.548366323, - 1.562544964, - 1.567374788, - 1.576555819, - 1.55120755, - 1.664792488, - 1.565593424, - 1.537245677, - 1.578319321, - 1.543088645, - 1.566553057, - 1.546977484, - 1.571786344, - 1.556018464, - 1.573481107, - 1.543199838, - 1.561688226, - 1.351302347, - 1.703494758 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "true", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.001975499875, - "scoreError" : 2.66339767461711E-4, - "scoreConfidence" : [ - 0.001709160107538289, - 0.002241839642461711 - ], - "scorePercentiles" : { - "0.0" : 2.66932E-4, - "50.0" : 0.001489844, - "90.0" : 0.0030389488, - "95.0" : 0.004422451049999992, - "99.0" : 0.00664482753, - "99.9" : 0.008097717, - "99.99" : 0.008097717, - "99.999" : 0.008097717, - "99.9999" : 0.008097717, - "100.0" : 0.008097717 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001401666, - 0.001415825, - 0.001284476, - 0.001301772, - 0.001320422, - 0.001375359, - 0.001266779, - 0.001258965, - 0.001298758, - 0.002953123, - 0.002610829, - 0.002914436, - 0.002985389, - 0.003031472, - 0.00299139, - 0.003087934, - 0.002903479, - 0.003039488, - 0.002670614, - 0.002720653, - 0.002733679, - 0.002721383, - 0.002759141, - 0.00300884, - 0.003075234, - 0.002877688, - 0.002980487, - 0.002808021, - 0.002747879, - 0.002726075, - 0.002842118, - 0.002841485, - 0.002840762, - 0.001588256, - 0.001710875, - 0.005051162, - 0.003079781, - 0.002134354, - 0.001285021, - 0.001365719 - ], - [ - 0.001277147, - 0.001394868, - 0.001342123, - 0.001277031, - 0.001402489, - 0.001454662, - 0.001494124, - 0.002741236, - 0.003328687, - 0.006598053, - 0.00257369, - 0.001339739, - 0.00128752, - 0.001301473, - 0.001287452, - 0.001243825, - 0.001487574, - 0.001331522, - 0.001298474, - 0.001416409, - 0.001495849, - 0.001470744, - 0.001245695, - 0.001439903, - 0.001493077, - 0.001467156, - 0.001472375, - 0.001397427, - 0.001270748, - 9.76366E-4, - 8.38791E-4, - 8.64177E-4, - 0.001004981, - 8.75463E-4, - 0.004636315, - 0.002289292, - 0.00235828, - 0.002205828, - 0.00170876, - 0.001241122 - ], - [ - 0.001381813, - 0.001323664, - 0.001272894, - 0.001291627, - 0.001410452, - 0.00139986, - 0.00182191, - 0.003034096, - 0.003070461, - 0.00271754, - 0.002286775, - 0.006055308, - 0.002269382, - 0.002118296, - 0.002084398, - 0.00192197, - 0.001923526, - 0.001794352, - 0.001928399, - 0.002013535, - 0.002203744, - 0.002341558, - 0.002180574, - 0.002094885, - 0.001845694, - 0.001987476, - 0.001935286, - 0.002011878, - 0.001526526, - 0.0017106, - 0.001450896, - 0.001553231, - 0.001547617, - 0.001390155, - 0.001274463, - 0.001641013, - 0.003725361, - 0.001351929, - 0.001535405, - 0.00147438 - ], - [ - 0.001358118, - 0.001280951, - 0.001290357, - 0.001364487, - 0.001276998, - 0.001310065, - 0.001440538, - 0.001578257, - 0.00519124, - 0.004981047, - 0.005326166, - 0.00445914, - 0.003367458, - 0.002193222, - 0.001165123, - 0.001107528, - 0.001114949, - 0.001066483, - 0.001160912, - 0.001377958, - 0.001323486, - 0.001238329, - 0.001213012, - 0.001157531, - 0.001169783, - 0.00111126, - 0.001151539, - 0.00130302, - 0.001064923, - 0.001144972, - 0.001133453, - 0.001170888, - 0.001117035, - 9.55362E-4, - 0.003088546, - 0.008097717, - 2.84108E-4, - 2.964E-4, - 2.66932E-4, - 2.93545E-4 - ], - [ - 0.001329094, - 0.001360755, - 0.001376846, - 0.001396416, - 0.0013696, - 0.001308377, - 0.001521833, - 0.002997717, - 0.002757817, - 0.002997863, - 0.0066453, - 0.002783396, - 0.002981914, - 0.001373828, - 0.001441978, - 0.00139553, - 0.001459629, - 0.001250817, - 0.00116881, - 0.002142046, - 0.0024121, - 0.002219585, - 0.002298004, - 0.001986299, - 0.002104407, - 0.002034858, - 0.002111139, - 0.002013131, - 0.001291772, - 0.001480431, - 0.001587929, - 0.001424662, - 0.001571878, - 0.001589774, - 0.001465993, - 0.00351309, - 0.001492114, - 0.001164858, - 0.00133334, - 0.001408042 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "true", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.006917230845000003, - "scoreError" : 0.0012009897783136405, - "scoreConfidence" : [ - 0.0057162410666863625, - 0.008118220623313643 - ], - "scorePercentiles" : { - "0.0" : 0.002985006, - "50.0" : 0.0055870780000000005, - "90.0" : 0.011227137300000006, - "95.0" : 0.018436645749999998, - "99.0" : 0.02665965001, - "99.9" : 0.043115984, - "99.99" : 0.043115984, - "99.999" : 0.043115984, - "99.9999" : 0.043115984, - "100.0" : 0.043115984 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.011412778, - 0.01153542, - 0.011655817, - 0.012892865, - 0.009655418, - 0.005211129, - 0.004760104, - 0.005367294, - 0.005196639, - 0.005167083, - 0.003878605, - 0.00606993, - 0.007245803, - 0.006898247, - 0.014355473, - 0.004088129, - 0.004393415, - 0.003575484, - 0.003256179, - 0.003511438, - 0.003994126, - 0.004282877, - 0.004964138, - 0.011599313, - 0.004063041, - 0.004265042, - 0.005062581, - 0.003357983, - 0.003401831, - 0.003872055, - 0.004954931, - 0.003814189, - 0.004965948, - 0.006900195, - 0.006566502, - 0.006726466, - 0.006054002, - 0.005592408, - 0.006614534, - 0.007080997 - ], - [ - 0.007679303, - 0.009197445, - 0.007052011, - 0.006417268, - 0.008473128, - 0.007964336, - 0.008569514, - 0.007850551, - 0.007997657, - 0.008516516, - 0.008876799, - 0.009927456, - 0.008903254, - 0.009665542, - 0.026353345, - 0.008863502, - 0.008776734, - 0.004545568, - 0.00477383, - 0.004391515, - 0.004411536, - 0.005597792, - 0.018450761, - 0.007422095, - 0.005159336, - 0.00498905, - 0.004591874, - 0.003582172, - 0.005683816, - 0.00460193, - 0.003330974, - 0.004114365, - 0.006237176, - 0.008053632, - 0.006520997, - 0.006803211, - 0.006153593, - 0.006634986, - 0.006350947, - 0.026662744 - ], - [ - 0.006733757, - 0.022111431, - 0.005477428, - 0.007123456, - 0.005520562, - 0.024530895, - 0.005293493, - 0.006227324, - 0.006098009, - 0.005392867, - 0.00633871, - 0.007736924, - 0.007699066, - 0.006085011, - 0.004583095, - 0.004586647, - 0.005000047, - 0.00338538, - 0.003758416, - 0.00338637, - 0.003622952, - 0.004479952, - 0.015814033, - 0.004062005, - 0.003855241, - 0.005335632, - 0.004479782, - 0.004471017, - 0.004377108, - 0.003406947, - 0.003731507, - 0.004445111, - 0.005894202, - 0.006554451, - 0.006393409, - 0.006795055, - 0.005359842, - 0.007119838, - 0.006175867, - 0.021975588 - ], - [ - 0.009822827, - 0.026353215, - 0.010463859, - 0.023351004, - 0.022401315, - 0.043115984, - 0.008522439, - 0.004217787, - 0.005252739, - 0.004638891, - 0.003677576, - 0.006866397, - 0.006300618, - 0.007130947, - 0.012333353, - 0.005265407, - 0.003506002, - 0.00368278, - 0.004169321, - 0.004196839, - 0.005235019, - 0.005581748, - 0.007986507, - 0.004651304, - 0.003342411, - 0.004287136, - 0.005665595, - 0.003820914, - 0.003752507, - 0.004328573, - 0.003856633, - 0.005706095, - 0.00647539, - 0.00647701, - 0.006361327, - 0.006274571, - 0.0074472, - 0.006295919, - 0.006449754, - 0.006907659 - ], - [ - 0.00674713, - 0.007894998, - 0.005501205, - 0.004879747, - 0.006353528, - 0.004094749, - 0.011311946, - 0.005798793, - 0.004922225, - 0.003919587, - 0.004458776, - 0.004414997, - 0.008198959, - 0.006706319, - 0.005982994, - 0.018168456, - 0.003831331, - 0.003604552, - 0.00384837, - 0.003790854, - 0.004070795, - 0.004622074, - 0.002985006, - 0.003007423, - 0.006015344, - 0.004011767, - 0.003288633, - 0.003441759, - 0.003393536, - 0.003140529, - 0.003308602, - 0.004255397, - 0.003853262, - 0.004644581, - 0.005219628, - 0.006918017, - 0.005757758, - 0.006064172, - 0.005262703, - 0.005755998 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "true", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.06533365067999998, - "scoreError" : 0.00876909528531831, - "scoreConfidence" : [ - 0.05656455539468167, - 0.0741027459653183 - ], - "scorePercentiles" : { - "0.0" : 0.03834186, - "50.0" : 0.049441226000000005, - "90.0" : 0.111427389, - "95.0" : 0.15186071694999986, - "99.0" : 0.22475019301000015, - "99.9" : 0.23846674, - "99.99" : 0.23846674, - "99.999" : 0.23846674, - "99.9999" : 0.23846674, - "100.0" : 0.23846674 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.051011, - 0.0463106, - 0.107659045, - 0.040378754, - 0.059420143, - 0.04012774, - 0.044067344, - 0.0979674, - 0.045095851, - 0.056687872, - 0.108056753, - 0.042961052, - 0.04969847, - 0.098348349, - 0.041520762, - 0.049501687, - 0.05137599, - 0.038611505, - 0.043119506, - 0.052044829, - 0.091369288, - 0.042749733, - 0.052344634, - 0.107793321, - 0.04350953, - 0.050286103, - 0.046596166, - 0.097684009, - 0.046536226, - 0.051724943, - 0.10582687, - 0.042173152, - 0.049250241, - 0.052437702, - 0.113537903, - 0.044447324, - 0.051060316, - 0.085752719, - 0.045129379, - 0.049949786 - ], - [ - 0.049471787, - 0.039082333, - 0.135616769, - 0.043139245, - 0.163464395, - 0.043306725, - 0.23846674, - 0.039853269, - 0.05124079, - 0.164467797, - 0.039292718, - 0.048490192, - 0.160306168, - 0.039540893, - 0.051372257, - 0.048071355, - 0.120995445, - 0.042200255, - 0.049711927, - 0.049452969, - 0.041699028, - 0.042404503, - 0.050494412, - 0.09506137, - 0.041000422, - 0.047809877, - 0.049429483, - 0.112201618, - 0.043437726, - 0.053112105, - 0.111062754, - 0.042931711, - 0.050925722, - 0.051629328, - 0.111467904, - 0.04307182, - 0.051720719, - 0.050006826, - 0.03987749, - 0.042523522 - ], - [ - 0.045585093, - 0.044293211, - 0.224921534, - 0.041436436, - 0.053698029, - 0.039813589, - 0.042023288, - 0.099840007, - 0.041298412, - 0.047692203, - 0.115332472, - 0.0410726, - 0.049212823, - 0.105370415, - 0.040569085, - 0.048762121, - 0.04610885, - 0.096448818, - 0.045077477, - 0.046889597, - 0.048069921, - 0.041187595, - 0.041933748, - 0.047957341, - 0.102047266, - 0.039608026, - 0.049892513, - 0.045525497, - 0.088289863, - 0.042262745, - 0.050812714, - 0.046308277, - 0.03834186, - 0.041724838, - 0.050676429, - 0.09897589, - 0.039379308, - 0.052451959, - 0.046828266, - 0.099390084 - ], - [ - 0.042900813, - 0.116421676, - 0.207787435, - 0.040735949, - 0.052844293, - 0.164006698, - 0.044092185, - 0.106181881, - 0.047717803, - 0.051762637, - 0.110821711, - 0.044648977, - 0.051223411, - 0.09957438, - 0.042147149, - 0.051694314, - 0.050398157, - 0.04052606, - 0.047610924, - 0.053759614, - 0.101913473, - 0.044031112, - 0.050385103, - 0.046001685, - 0.170647841, - 0.046484926, - 0.050495178, - 0.102086881, - 0.044154245, - 0.053693529, - 0.049476115, - 0.116644356, - 0.044262068, - 0.052691015, - 0.138472683, - 0.040899097, - 0.049698848, - 0.054124162, - 0.103830695, - 0.043440344 - ], - [ - 0.043973706, - 0.152501893, - 0.10496182, - 0.041643842, - 0.059687052, - 0.043584809, - 0.043489163, - 0.139678372, - 0.043394892, - 0.051796038, - 0.10882438, - 0.041434739, - 0.048005715, - 0.104259845, - 0.04257503, - 0.050700241, - 0.050022375, - 0.043464284, - 0.04636882, - 0.052033313, - 0.101125449, - 0.040186625, - 0.049156533, - 0.048231051, - 0.097147417, - 0.044527886, - 0.047054541, - 0.173692731, - 0.040020275, - 0.047449589, - 0.048990676, - 0.09056671, - 0.042069196, - 0.051154188, - 0.048281215, - 0.038986263, - 0.042949282, - 0.050492602, - 0.089763892, - 0.041547697 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "true", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 3.118503043890001, - "scoreError" : 0.19475524037441355, - "scoreConfidence" : [ - 2.9237478035155875, - 3.3132582842644145 - ], - "scorePercentiles" : { - "0.0" : 1.030565182, - "50.0" : 3.1799393735, - "90.0" : 4.1218905797, - "95.0" : 4.2707296976, - "99.0" : 4.8388487529200015, - "99.9" : 4.873043921, - "99.99" : 4.873043921, - "99.999" : 4.873043921, - "99.9999" : 4.873043921, - "100.0" : 4.873043921 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 3.281764911, - 2.74208574, - 3.759642933, - 3.948703235, - 2.72539751, - 2.421081972, - 3.302984787, - 2.731908492, - 2.851662548, - 3.433921313, - 3.140736444, - 2.602092846, - 3.548672411, - 3.098314474, - 2.319537473, - 3.636059237, - 3.166488424, - 2.262288435, - 3.426204884, - 3.228311536, - 2.402108924, - 4.082365141, - 1.673298106, - 3.820565883, - 2.620399285, - 1.212154519, - 2.78811124, - 3.588497271, - 3.462635261, - 2.754974355, - 4.147285212, - 1.731054365, - 4.257479484, - 2.578328006, - 1.366030038, - 2.849544573, - 3.769514092, - 1.962366798, - 4.129450952, - 2.750369829 - ], - [ - 3.541165544, - 2.980787315, - 4.12283767, - 3.849386591, - 3.977295173, - 3.373618378, - 2.58711161, - 3.97881138, - 3.751618363, - 3.16664718, - 2.663751254, - 3.781389147, - 3.592998607, - 3.122391641, - 2.453576719, - 3.618495132, - 3.583524934, - 3.065960623, - 2.407832546, - 3.665161291, - 3.467312209, - 3.047739169, - 2.527755456, - 4.098727487, - 3.580418427, - 3.184815481, - 2.737850472, - 3.908569824, - 1.798925323, - 4.032202652, - 2.144819987, - 3.833900927, - 1.743475757, - 3.901270296, - 2.523284575, - 3.327814001, - 1.684705253, - 3.79371242, - 2.788805844, - 3.276808535 - ], - [ - 3.828158252, - 3.156706166, - 3.971010841, - 3.513213995, - 2.992971121, - 4.113366767, - 3.729539242, - 2.663797271, - 4.445422416, - 3.501609178, - 2.583810073, - 3.643960201, - 3.28878928, - 2.537700853, - 3.474173652, - 3.073739136, - 2.130879655, - 3.071312844, - 2.837445046, - 4.734316031, - 3.374920133, - 2.588374412, - 3.47279102, - 3.175063266, - 2.541844528, - 3.451316317, - 2.929593154, - 3.277790405, - 1.229616169, - 4.26221047, - 2.690935695, - 1.205244419, - 2.408529964, - 3.562578413, - 1.561319238, - 4.082211158, - 2.332662815, - 1.030565182, - 4.547714899, - 3.771704448 - ], - [ - 2.763221632, - 4.044227382, - 3.465942819, - 3.163278125, - 2.766615855, - 4.065821996, - 4.873043921, - 3.94161219, - 3.450020496, - 3.074012725, - 2.779535707, - 4.091324096, - 3.923585522, - 3.40697932, - 2.999746702, - 2.538479428, - 4.839904639, - 3.846272153, - 3.281684196, - 2.795543012, - 4.382601151, - 4.34247533, - 2.25168232, - 1.135692461, - 4.158029509, - 2.683307135, - 4.193596352, - 2.051747255, - 1.158308252, - 2.691152943, - 4.250021266, - 2.571743387, - 3.204059474, - 1.55304217, - 4.208436135, - 2.507491487, - 3.940063611, - 2.031542286, - 1.106264639, - 2.65705081 - ], - [ - 3.990630206, - 3.340243396, - 2.916687734, - 4.201327056, - 4.281978249, - 3.81723795, - 2.838432064, - 2.550997456, - 3.716530107, - 3.215642238, - 2.932444773, - 2.635569112, - 3.604833545, - 3.530758669, - 3.004124541, - 2.52942215, - 3.71875111, - 3.479600867, - 3.064844365, - 2.750844519, - 3.620446325, - 3.469340794, - 2.682974887, - 3.379065568, - 2.370677381, - 1.429122001, - 4.289682256, - 3.021476979, - 3.298600348, - 1.741967521, - 4.271178078, - 2.96758695, - 1.42944417, - 3.234014385, - 2.803745708, - 3.699997484, - 2.130642359, - 1.20644986, - 2.609283004, - 3.684276467 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "false", - "size" : "10000" - }, - "primaryMetric" : { - "score" : 0.001290203700000001, - "scoreError" : 1.9764988264629946E-4, - "scoreConfidence" : [ - 0.0010925538173537017, - 0.0014878535826463005 - ], - "scorePercentiles" : { - "0.0" : 6.39287E-4, - "50.0" : 0.0012657305, - "90.0" : 0.0022528047000000013, - "95.0" : 0.0027336779, - "99.0" : 0.005318277850000001, - "99.9" : 0.005702705, - "99.99" : 0.005702705, - "99.999" : 0.005702705, - "99.9999" : 0.005702705, - "100.0" : 0.005702705 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.001299492, - 0.001388309, - 0.001306023, - 0.001306398, - 0.001332537, - 0.001316862, - 0.001286687, - 0.00133182, - 0.001378444, - 0.001477978, - 0.001559193, - 0.001348817, - 0.001336416, - 0.005221639, - 0.001256685, - 9.36144E-4, - 8.09546E-4, - 0.002707837, - 0.00238808, - 0.002433218, - 0.002915752, - 0.002539435, - 9.72415E-4, - 7.84641E-4, - 6.92821E-4, - 7.28115E-4, - 7.35539E-4, - 7.73495E-4, - 8.36389E-4, - 7.62142E-4, - 8.78282E-4, - 7.72631E-4, - 7.62894E-4, - 7.53162E-4, - 7.50756E-4, - 7.54284E-4, - 8.67382E-4, - 7.85804E-4, - 7.34395E-4, - 7.22422E-4 - ], - [ - 0.001372636, - 0.001513913, - 0.001351966, - 0.001317527, - 0.00142476, - 0.001348867, - 0.001357163, - 0.002011907, - 0.00138029, - 0.001478391, - 0.001339405, - 0.001335263, - 0.001379854, - 0.005702705, - 0.001560218, - 8.09396E-4, - 0.002725221, - 0.002484049, - 0.002592943, - 0.002583037, - 0.002278904, - 8.94212E-4, - 8.09362E-4, - 7.02691E-4, - 6.77646E-4, - 6.49363E-4, - 7.02493E-4, - 6.42384E-4, - 6.43185E-4, - 7.39404E-4, - 7.46629E-4, - 8.90078E-4, - 7.36389E-4, - 6.50039E-4, - 6.45593E-4, - 7.30259E-4, - 6.43727E-4, - 7.42933E-4, - 6.90253E-4, - 6.39287E-4 - ], - [ - 0.001300567, - 0.001328425, - 0.001319473, - 0.001293027, - 0.001395946, - 0.001356139, - 0.001334933, - 0.001405565, - 0.001637387, - 0.001543812, - 0.001552077, - 0.00166761, - 0.001333263, - 0.005319254, - 8.35924E-4, - 8.00283E-4, - 0.001122114, - 0.001379564, - 0.001414979, - 0.001430964, - 0.002017911, - 0.001547364, - 0.001593964, - 0.001332291, - 8.30307E-4, - 7.74868E-4, - 8.44879E-4, - 8.335E-4, - 7.68915E-4, - 8.67883E-4, - 8.60139E-4, - 7.58848E-4, - 7.56007E-4, - 8.61845E-4, - 7.53628E-4, - 7.52418E-4, - 8.35577E-4, - 7.14299E-4, - 6.81357E-4, - 6.74103E-4 - ], - [ - 0.001391481, - 0.001302875, - 0.001294259, - 0.001301367, - 0.001435203, - 0.001297713, - 0.001277997, - 0.001646835, - 0.001373628, - 0.001474431, - 0.001511257, - 0.001274776, - 0.001405531, - 0.005090855, - 0.001073659, - 7.90428E-4, - 9.86348E-4, - 0.002838854, - 0.00293045, - 0.002577329, - 0.002762762, - 0.002734123, - 0.001077079, - 8.58901E-4, - 6.98747E-4, - 6.82085E-4, - 7.42039E-4, - 6.4825E-4, - 7.16821E-4, - 7.36753E-4, - 6.43428E-4, - 6.51909E-4, - 6.47232E-4, - 6.43085E-4, - 6.51435E-4, - 7.3783E-4, - 7.36126E-4, - 6.45657E-4, - 6.45755E-4, - 6.49472E-4 - ], - [ - 0.001329573, - 0.001456629, - 0.001341745, - 0.001311032, - 0.001337174, - 0.00138848, - 0.001430912, - 0.001441693, - 0.001437107, - 0.001864244, - 0.001517484, - 0.001320136, - 0.001610544, - 0.005201429, - 0.001057872, - 7.841E-4, - 9.38933E-4, - 0.001632412, - 0.001713534, - 0.001366513, - 0.001383716, - 0.001412087, - 0.00140325, - 0.001410555, - 6.95913E-4, - 8.43913E-4, - 0.001209493, - 9.41706E-4, - 7.92333E-4, - 7.40659E-4, - 6.39848E-4, - 6.57374E-4, - 6.75113E-4, - 6.88066E-4, - 8.10474E-4, - 8.48903E-4, - 8.70925E-4, - 8.34066E-4, - 7.16313E-4, - 6.9909E-4 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "false", - "size" : "100000" - }, - "primaryMetric" : { - "score" : 0.013283434414999988, - "scoreError" : 0.0012644901107058577, - "scoreConfidence" : [ - 0.01201894430429413, - 0.014547924525705845 - ], - "scorePercentiles" : { - "0.0" : 0.008712821, - "50.0" : 0.011115049, - "90.0" : 0.023471288200000023, - "95.0" : 0.027428245599999998, - "99.0" : 0.030596894000000003, - "99.9" : 0.030782686, - "99.99" : 0.030782686, - "99.999" : 0.030782686, - "99.9999" : 0.030782686, - "100.0" : 0.030782686 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.010877454, - 0.014261024, - 0.015818099, - 0.028699819, - 0.009563532, - 0.009739953, - 0.008829752, - 0.010400688, - 0.027712978, - 0.013219714, - 0.010557731, - 0.01147284, - 0.010815546, - 0.012096505, - 0.016049704, - 0.018682522, - 0.019691938, - 0.018316203, - 0.030600913, - 0.009731809, - 0.008983838, - 0.009562971, - 0.008747733, - 0.011214711, - 0.010606051, - 0.009289203, - 0.01204435, - 0.010736594, - 0.030199013, - 0.010102783, - 0.009264729, - 0.009629758, - 0.010169415, - 0.010375838, - 0.010947081, - 0.010023974, - 0.012103386, - 0.012498534, - 0.012698387, - 0.016951384 - ], - [ - 0.011308738, - 0.016893577, - 0.019360017, - 0.030782686, - 0.010868631, - 0.010133697, - 0.008802076, - 0.010375389, - 0.024534867, - 0.011188456, - 0.011438165, - 0.012961537, - 0.012907328, - 0.011957646, - 0.017342017, - 0.017870895, - 0.016747922, - 0.016033018, - 0.028855722, - 0.01112204, - 0.010279406, - 0.010391552, - 0.011103225, - 0.01201792, - 0.012497928, - 0.01074893, - 0.011918236, - 0.011847682, - 0.024803529, - 0.009180946, - 0.010206647, - 0.010528975, - 0.010208289, - 0.009177414, - 0.009530563, - 0.01108725, - 0.012160088, - 0.012378307, - 0.010348344, - 0.015231263 - ], - [ - 0.011769557, - 0.016649424, - 0.017630368, - 0.028861635, - 0.010706389, - 0.011550727, - 0.010743143, - 0.011122181, - 0.023891216, - 0.009801922, - 0.009077589, - 0.010850404, - 0.009001948, - 0.012424733, - 0.015836005, - 0.017816469, - 0.016116691, - 0.015232582, - 0.027281748, - 0.010257403, - 0.009240193, - 0.009167537, - 0.010257658, - 0.009002143, - 0.009702215, - 0.008914039, - 0.009066692, - 0.009696675, - 0.026923424, - 0.008712821, - 0.011830018, - 0.01046944, - 0.009814897, - 0.009563084, - 0.009669797, - 0.008802222, - 0.009661952, - 0.009972455, - 0.009402265, - 0.01334145 - ], - [ - 0.009522169, - 0.013539846, - 0.018328084, - 0.028774591, - 0.009637861, - 0.009126078, - 0.0091565, - 0.01156447, - 0.026079666, - 0.009113414, - 0.009800941, - 0.010405052, - 0.009789772, - 0.011260722, - 0.017607014, - 0.019033593, - 0.01835076, - 0.017877576, - 0.027435956, - 0.009874727, - 0.009063324, - 0.010236911, - 0.011073682, - 0.011392473, - 0.010743939, - 0.011346561, - 0.011316382, - 0.010003549, - 0.024060862, - 0.009454031, - 0.010843483, - 0.010751175, - 0.012018264, - 0.010091222, - 0.009464219, - 0.010710867, - 0.011529092, - 0.011571038, - 0.009381391, - 0.015774855 - ], - [ - 0.009448034, - 0.014475642, - 0.016388746, - 0.028772961, - 0.009082472, - 0.010820601, - 0.010213443, - 0.013908627, - 0.025099779, - 0.011739809, - 0.01141594, - 0.011638817, - 0.010828969, - 0.011284496, - 0.016793835, - 0.017225601, - 0.014900782, - 0.015695342, - 0.025564862, - 0.010026516, - 0.010792755, - 0.012825416, - 0.011889619, - 0.012496493, - 0.010696617, - 0.012536696, - 0.011108058, - 0.011514432, - 0.024653077, - 0.010647024, - 0.009373218, - 0.009227552, - 0.012529846, - 0.008910833, - 0.01043831, - 0.010226221, - 0.010122959, - 0.009374816, - 0.010466467, - 0.014172602 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "false", - "size" : "1000000" - }, - "primaryMetric" : { - "score" : 0.15883304821, - "scoreError" : 0.018444092854494196, - "scoreConfidence" : [ - 0.1403889553555058, - 0.1772771410644942 - ], - "scorePercentiles" : { - "0.0" : 0.107444091, - "50.0" : 0.1206347005, - "90.0" : 0.311707399, - "95.0" : 0.33679791354999994, - "99.0" : 0.36008588935, - "99.9" : 0.382049645, - "99.99" : 0.382049645, - "99.999" : 0.382049645, - "99.9999" : 0.382049645, - "100.0" : 0.382049645 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 0.313117492, - 0.115910979, - 0.123221344, - 0.331234895, - 0.127629376, - 0.128440232, - 0.113549949, - 0.117523247, - 0.127264008, - 0.325621195, - 0.117481526, - 0.123789087, - 0.282433742, - 0.130414568, - 0.116907584, - 0.116873695, - 0.139513513, - 0.139417266, - 0.130058789, - 0.122661003, - 0.118587534, - 0.29187321, - 0.127755149, - 0.123073069, - 0.12289167, - 0.273744962, - 0.120064945, - 0.116738861, - 0.118908888, - 0.123145215, - 0.116569002, - 0.122239863, - 0.115124065, - 0.135041642, - 0.284335597, - 0.124124144, - 0.119150211, - 0.12379694, - 0.283935169, - 0.117858765 - ], - [ - 0.315230139, - 0.115566829, - 0.13609745, - 0.308289577, - 0.113426185, - 0.123676593, - 0.115294319, - 0.123273047, - 0.135743267, - 0.359449156, - 0.114677973, - 0.119117039, - 0.278564713, - 0.113407744, - 0.120779341, - 0.113036161, - 0.156997632, - 0.123790105, - 0.116795968, - 0.118530372, - 0.114440937, - 0.320629501, - 0.120207058, - 0.122655217, - 0.117595628, - 0.258467532, - 0.118310717, - 0.127488294, - 0.114087032, - 0.118046753, - 0.113104328, - 0.120721694, - 0.114649889, - 0.112620497, - 0.329471249, - 0.112807585, - 0.115012205, - 0.118764413, - 0.285852104, - 0.113821195 - ], - [ - 0.312087157, - 0.124091118, - 0.120828011, - 0.351202285, - 0.128046623, - 0.2822025, - 0.113008356, - 0.114311925, - 0.140206145, - 0.360092321, - 0.118825937, - 0.109378477, - 0.277892489, - 0.116957737, - 0.125896375, - 0.117393322, - 0.139710826, - 0.132399264, - 0.117863083, - 0.116879692, - 0.109501864, - 0.314630623, - 0.109139344, - 0.120547707, - 0.119713154, - 0.253495782, - 0.119825808, - 0.131125263, - 0.130192611, - 0.116486685, - 0.11416192, - 0.122043608, - 0.11324241, - 0.115712085, - 0.337090704, - 0.11259867, - 0.113533689, - 0.128175614, - 0.283062777, - 0.112438606 - ], - [ - 0.119137666, - 0.108754227, - 0.115837006, - 0.328399632, - 0.115828154, - 0.112980323, - 0.109464067, - 0.112188354, - 0.132787871, - 0.314700971, - 0.114873875, - 0.109896172, - 0.114826245, - 0.116978768, - 0.115819311, - 0.111215433, - 0.122471744, - 0.352184791, - 0.108945853, - 0.109387206, - 0.115262318, - 0.29027034, - 0.109443077, - 0.111375128, - 0.112427769, - 0.278144219, - 0.117496898, - 0.111518873, - 0.123072439, - 0.121691103, - 0.107444091, - 0.109016733, - 0.113014285, - 0.121579866, - 0.347889571, - 0.11077372, - 0.121051997, - 0.127884536, - 0.28157333, - 0.114277222 - ], - [ - 0.302884354, - 0.113137729, - 0.134106771, - 0.349732575, - 0.125827537, - 0.274326542, - 0.123094715, - 0.120133065, - 0.145744069, - 0.382049645, - 0.127205065, - 0.119653978, - 0.281435689, - 0.120225012, - 0.129051994, - 0.119975699, - 0.158425045, - 0.116482486, - 0.117913069, - 0.116735693, - 0.114738549, - 0.338544642, - 0.120330245, - 0.121564369, - 0.12338998, - 0.292438102, - 0.11483736, - 0.11982044, - 0.118732615, - 0.28292417, - 0.128582349, - 0.127129719, - 0.131131973, - 0.117809315, - 0.110453838, - 0.117042797, - 0.114744184, - 0.120765629, - 0.353935843, - 0.119155211 - ] - ] - }, - "secondaryMetrics" : { - } - }, - { - "jmhVersion" : "1.32", - "benchmark" : "bench.MidtermPart2Benchmark.containsBenchmark", - "mode" : "ss", - "threads" : 1, - "forks" : 5, - "jvm" : "/usr/local/Cellar/openjdk@8/1.8.0+322/libexec/openjdk.jdk/Contents/Home/jre/bin/java", - "jvmArgs" : [ - ], - "jdkVersion" : "1.8.0_322", - "vmName" : "OpenJDK 64-Bit Server VM", - "vmVersion" : "25.322-b00", - "warmupIterations" : 5, - "warmupTime" : "single-shot", - "warmupBatchSize" : 1, - "measurementIterations" : 40, - "measurementTime" : "single-shot", - "measurementBatchSize" : 1, - "params" : { - "collection" : "List", - "parallel" : "false", - "size" : "10000000" - }, - "primaryMetric" : { - "score" : 6.026310806905001, - "scoreError" : 0.3463742154975086, - "scoreConfidence" : [ - 5.679936591407492, - 6.37268502240251 - ], - "scorePercentiles" : { - "0.0" : 2.195729618, - "50.0" : 5.724309503, - "90.0" : 7.9174551285, - "95.0" : 8.09821062985, - "99.0" : 8.52817301045, - "99.9" : 8.55481943, - "99.99" : 8.55481943, - "99.999" : 8.55481943, - "99.9999" : 8.55481943, - "100.0" : 8.55481943 - }, - "scoreUnit" : "s/op", - "rawData" : [ - [ - 8.285695215, - 7.635742916, - 5.036329984, - 7.832147022, - 5.204497379, - 7.958329486, - 5.283771915, - 8.085572416, - 5.457197623, - 8.148941217, - 5.506328159, - 2.210497503, - 6.736231538, - 6.685949652, - 4.077427515, - 2.344255734, - 6.50423714, - 4.089204557, - 2.482031746, - 4.181193653, - 2.631726747, - 4.372334027, - 2.889888675, - 4.602637347, - 3.051618866, - 4.696019336, - 3.284502416, - 4.919811834, - 7.022937661, - 5.120250116, - 7.155879184, - 5.363780291, - 7.200244878, - 5.479798513, - 7.29457975, - 5.54005452, - 8.403423642, - 5.636421042, - 8.55481943, - 5.13924676 - ], - [ - 6.738031609, - 6.582334805, - 6.719271452, - 6.876754526, - 6.961210091, - 7.101547234, - 7.111378847, - 4.743532664, - 3.400178542, - 7.374192851, - 5.061012359, - 3.866764676, - 7.998373718, - 5.413859162, - 7.326121779, - 5.581298755, - 7.130968719, - 5.715646745, - 7.435376236, - 5.817036641, - 8.077139979, - 5.320502226, - 5.574163332, - 7.550233891, - 4.920848859, - 5.007715252, - 7.826555912, - 5.171988135, - 5.23902463, - 7.926933807, - 5.329117223, - 5.412516362, - 7.706551387, - 5.65283996, - 3.894731408, - 2.195729618, - 3.986431485, - 6.882760239, - 4.22280703, - 6.576675542 - ], - [ - 6.861191843, - 6.811163166, - 6.786813687, - 6.710027566, - 6.917315875, - 6.789623663, - 7.117887945, - 4.740242018, - 3.314600724, - 7.124864673, - 4.910444471, - 7.132516809, - 5.188947322, - 7.300873469, - 5.339281275, - 7.277918256, - 5.628479212, - 7.101367429, - 5.63729134, - 7.394179364, - 5.720417839, - 6.875431413, - 5.333971903, - 5.579200852, - 8.477822744, - 4.894784229, - 4.873543916, - 7.704917763, - 5.151749153, - 5.18185082, - 7.976483241, - 5.278944519, - 5.375465859, - 8.009371213, - 5.370006755, - 5.660693568, - 6.783858924, - 4.05526317, - 6.82419986, - 4.198098815 - ], - [ - 6.896201319, - 6.967656715, - 7.000773659, - 7.082255674, - 7.1862108, - 7.279889816, - 7.335353799, - 4.987773111, - 3.51432315, - 7.50461775, - 8.075588649, - 5.419069012, - 7.50248288, - 5.559972628, - 7.496256993, - 5.632113646, - 7.235718566, - 5.897645542, - 6.947626715, - 5.954013678, - 8.176914806, - 5.51805391, - 5.793740995, - 7.81898335, - 5.081027599, - 5.230257067, - 8.098875799, - 5.345468502, - 5.362096447, - 8.080075447, - 5.413902284, - 5.424734454, - 7.813746431, - 5.728201167, - 3.873918436, - 2.274673908, - 4.207974885, - 7.045511552, - 4.320286405, - 6.925332226 - ], - [ - 6.970574455, - 7.187932702, - 7.293079756, - 7.334236443, - 7.309777887, - 7.4630996, - 5.069931648, - 3.746790604, - 7.40902084, - 5.331615324, - 7.650840811, - 5.446247124, - 7.440991586, - 5.662209412, - 7.424562082, - 5.880883217, - 7.002866528, - 5.401294891, - 5.507158374, - 8.528681599, - 4.978763028, - 5.025453655, - 8.000312518, - 5.232505966, - 5.149922666, - 8.144202122, - 5.364726937, - 5.339937969, - 8.124428705, - 5.416360123, - 5.689642941, - 6.898983454, - 4.049313881, - 6.960029103, - 4.306869112, - 7.062990377, - 4.375023522, - 6.916763286, - 4.403904511, - 6.804091094 - ] - ] - }, - "secondaryMetrics" : { - } - } -] - - diff --git a/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.png b/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.png deleted file mode 100644 index c9a31afe81a8b8b46ab9482eb33f58c711190552..0000000000000000000000000000000000000000 Binary files a/previous-exams/2022-midterm-code/bench-results/Part2BenchmarkResults.png and /dev/null differ diff --git a/previous-exams/2022-midterm-code/build.sbt b/previous-exams/2022-midterm-code/build.sbt deleted file mode 100644 index 674678d47602d6e07695ed620f782831e43ef476..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/build.sbt +++ /dev/null @@ -1,19 +0,0 @@ -val scala3Version = "3.1.2" - -enablePlugins(JmhPlugin) - -lazy val root = project - .in(file(".")) - .settings( - name := "code", - version := "0.1.0-SNAPSHOT", - - scalaVersion := scala3Version, - - libraryDependencies += "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.3", - libraryDependencies += "junit" % "junit" % "4.13" % Test, - libraryDependencies += "com.github.sbt" % "junit-interface" % "0.13.3" % Test, - - Test / parallelExecution := false, - Test / testOptions += Tests.Argument(TestFrameworks.JUnit) - ) diff --git a/previous-exams/2022-midterm-code/project/plugins.sbt b/previous-exams/2022-midterm-code/project/plugins.sbt deleted file mode 100644 index 967e66f4bd3f217063f30b41347240b6fb09dc61..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/project/plugins.sbt +++ /dev/null @@ -1,2 +0,0 @@ -addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") diff --git a/previous-exams/2022-midterm-code/src/main/scala/bench/AbstractCollectionBenchmark.scala b/previous-exams/2022-midterm-code/src/main/scala/bench/AbstractCollectionBenchmark.scala deleted file mode 100644 index 85e89d47adcf91abdde7cc13a8e7c4e270dd7276..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/bench/AbstractCollectionBenchmark.scala +++ /dev/null @@ -1,23 +0,0 @@ -package bench - -import org.openjdk.jmh.annotations.* - -@State(Scope.Benchmark) -//@Fork(jvmArgsAppend = Array("-Djava.util.concurrent.ForkJoinPool.common.parallelism=4")) -abstract class AbstractCollectionBenchmark: - @Param(Array("10000", "100000", "1000000", "10000000")) - var size: Int = _ - - @Param(Array("Vector", "Array", "ArrayBuffer", "List")) - var collection: String = _ - - var haystack: Iterable[Int] = _ - - @Setup(Level.Invocation) - def setup() = - val gen = (1 to (size * 2) by 2) - haystack = collection match - case "Vector" => gen.toVector - case "Array" => gen.toArray - case "ArrayBuffer" => gen.toBuffer - case "List" => gen.toList diff --git a/previous-exams/2022-midterm-code/src/main/scala/bench/CollectionBenchmark.scala b/previous-exams/2022-midterm-code/src/main/scala/bench/CollectionBenchmark.scala deleted file mode 100644 index ab8dec0ffeaaad939aec6efa20534bf4b7531942..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/bench/CollectionBenchmark.scala +++ /dev/null @@ -1,12 +0,0 @@ -package bench - -import org.openjdk.jmh.annotations.* - -class CollectionBenchmark extends AbstractCollectionBenchmark: - @Benchmark - def take() = - haystack.take(size / 2) - - @Benchmark - def drop() = - haystack.drop(size / 2) diff --git a/previous-exams/2022-midterm-code/src/main/scala/bench/Part2Benchmark.scala b/previous-exams/2022-midterm-code/src/main/scala/bench/Part2Benchmark.scala deleted file mode 100644 index 6ab99775ee6e60a161694b936bbe6047e63fe23b..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/bench/Part2Benchmark.scala +++ /dev/null @@ -1,20 +0,0 @@ -package bench - -import midterm.contains - -import org.openjdk.jmh.annotations.* - -class MidtermPart2Benchmark extends AbstractCollectionBenchmark: - val needle = 10 - - @Param(Array("true", "false")) - var parallel: Boolean = _ - - @Setup(Level.Invocation) - override def setup() = - super.setup() - midterm.parallelismEnabled = parallel - - @Benchmark - def containsBenchmark() = - contains(haystack, needle) diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock1.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock1.scala deleted file mode 100644 index b24f3b466a6e1143432941bdfb399137ea8573a2..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock1.scala +++ /dev/null @@ -1,14 +0,0 @@ -package midterm - -import scala.collection.mutable.Set - -@main def mock1() = - val values = Set[Int]() - for _ <- 1 to 100000 do - var sum = 0 - val t1 = task { sum += 1 } - val t2 = task { sum += 1 } - t1.join() - t2.join() - values += sum - println(values) diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock2.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock2.scala deleted file mode 100644 index 906edbb6cbddd25a83de7bba084477d332e2b569..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Mock2.scala +++ /dev/null @@ -1,20 +0,0 @@ -package midterm - -import midterm.instrumentation.Monitor - -class Account(private var amount: Int = 0) extends Monitor: - def transfer(target: Account, n: Int) = - this.synchronized { - target.synchronized { - this.amount -= n - target.amount += n - } - } - -@main def mock2() = - val a = new Account(50) - val b = new Account(70) - val t1 = task { a.transfer(b, 10) } - val t2 = task { b.transfer(a, 10) } - t1.join() - t2.join() diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part1.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part1.scala deleted file mode 100644 index 4ada8b344cf3eae1750ee507e7b10b22495ce336..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part1.scala +++ /dev/null @@ -1,45 +0,0 @@ -package midterm - -import scala.collection.parallel.Task -import scala.collection.parallel.CollectionConverters.* - -// Questions 1-3 - -// See tests in midterm.Part1Test. -// Run with `sbt "testOnly midterm.Part1Test"`. - -def parallel3[A, B, C](op1: => A, op2: => B, op3: => C): (A, B, C) = - val res1 = task { op1 } - val res2 = task { op2 } - val res3 = op3 - (res1.join(), res2.join(), res3) - -def find(arr: Array[Int], value: Int, threshold: Int): Option[Int] = - def findHelper(start: Int, end: Int): Option[Int] = - if end - start <= threshold then - var i = start - while i < end do - if arr(i) == value then return Some(value) - i += 1 - None - else - val inc = (end - start) / 3 - val (res1, res2, res3) = parallel3( - findHelper(start, start + inc), - findHelper(start + inc, start + 2 * inc), - findHelper(start + 2 * inc, end) - ) - res1.orElse(res2).orElse(res3) - findHelper(0, arr.size) - -def findAggregated(arr: Array[Int], value: Int): Option[Int] = - val no: Option[Int] = None - val yes: Option[Int] = Some(value) - def f = (x1: Option[Int], x2: Int) => if x2 == value then Some(x2) else x1 - def g = (x1: Option[Int], x2: Option[Int]) => if x1 != None then x1 else x2 - arr.par.aggregate(no)(f, g) - -@main def part1() = - println(find(Array(1, 2, 3), 2, 1)) - -// See tests in Part1Test diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part2.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part2.scala deleted file mode 100644 index 8aee7054cd01ec0477cbedf07df2b6927f759c5e..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part2.scala +++ /dev/null @@ -1,45 +0,0 @@ -package midterm - -// Questions 4-7 - -// See tests in midterm.Part2Test. -// Run with `sbt "testOnly midterm.Part2Test"`. - -/* -Answers to the exam questions: - When called with a Vector: - The total amount of work is O(n), as it is dominated by the time needed to - read the array. More precisely W(n) = c + 2*W(n/2) = O(n). - - The depth is O(log(n)), because every recursion takes constant time - and we divide the size of the input by 2 every time, i.e. D(n) = c + D(n/2) = O(log(n)). - - Note however that in practice it is often still faster to manipulate - start and end indices rather than using take and drop. - - When called with a List: - Every recursion takes up to time O(n) rather than constant time. - - The total amount of work is O(n) times the number of recursion, because - take and drop takes time O(n) on lists. Precisely, W(n) = n + 2*W(n/2) = O(log(n)*n) - - The depth is computed similarly: D(n) = n + D(n/2) = O(n), i.e. - -Note: these are theoretical results. In practice, you should always double-check -that kind of conclusions with benchmarks. We did so in -`midterm-code/src/main/scala/bench`. Results are available in `bench-results`. -From these results, we can conclude that -1. Vectors are indeed faster in this case, and -2. parallelization of `contains` yields a 2x speedup. - */ -def contains[A](l: Iterable[A], elem: A): Boolean = - val n = l.size - if n <= 5 then - for i <- l do if i == elem then return true - false - else - val (p0, p1) = parallel( - contains(l.take(n / 2), elem), - contains(l.drop(n / 2), elem) - ) - p0 || p1 diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part3.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part3.scala deleted file mode 100644 index 077e3874d013b191a187b5673aff92d44a99d669..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part3.scala +++ /dev/null @@ -1,14 +0,0 @@ -package midterm - -// Question 8 - -// Run with `sbt "runMain midterm.part3"` - -@main def part3() = - def thread(b: => Unit) = - val t = new Thread: - override def run() = b - t - val t = thread { println(s"Hello World") } - t.join() - println(s"Hello") diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part4.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part4.scala deleted file mode 100644 index 7bf958a6b8934dc8839e8f4f7ef3e516d3338f04..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part4.scala +++ /dev/null @@ -1,22 +0,0 @@ -package midterm - -import java.util.concurrent.atomic.AtomicInteger -import instrumentation.* - -// Questions 9-15 - -// See tests in midterm.Part4Test. -// Run with `sbt "testOnly midterm.Part4Test"`. - -class Node( - // Globally unique identifier. Different for each instance. - val guid: Int -) extends Monitor - -// This function might be called concurrently. -def lockFun(nodes: List[Node], fn: (e: Int) => Unit): Unit = - if nodes.size > 0 then - nodes.head.synchronized { - fn(nodes(0).guid) - lockFun(nodes.tail, fn) - } diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part6.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part6.scala deleted file mode 100644 index 4725433f7b4d8818618acec01cb47b01ef2ce415..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part6.scala +++ /dev/null @@ -1,20 +0,0 @@ -package midterm - -import midterm.instrumentation.Monitor - -// Question 21 - -// See tests in midterm.Part6Test. -// Run with `sbt "testOnly midterm.Part6Test"`. - -class TicketsManager(totalTickets: Int) extends Monitor: - var remainingTickets = totalTickets - - // This method might be called concurrently - def getTicket(): Boolean = - if remainingTickets > 0 then - this.synchronized { - remainingTickets -= 1 - } - true - else false diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part7.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part7.scala deleted file mode 100644 index a6c2e923232c7634d1b5f558a4ea0ff15c1397d0..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part7.scala +++ /dev/null @@ -1,47 +0,0 @@ -package midterm - -import midterm.instrumentation.Monitor - -// Questions 22-24 - -// See tests in midterm.Part7Test. -// Run with `sbt "testOnly midterm.Part7Test"`. - -class NIC(private val _index: Int, private var _assigned: Boolean) - extends Monitor: - def index = _index - def assigned = _assigned - def assigned_=(v: Boolean) = _assigned = v - -class NICManager(n: Int): - // Creates a list with n NICs - val nics = (for i <- 0 until n yield NIC(i, false)).toList - - // This method might be called concurrently - def assignNICs(limitRecvNICs: Boolean = false): (Int, Int) = - var recvNIC: Int = 0 - var sendNIC: Int = 0 - var gotRecvNIC: Boolean = false - var gotSendNIC: Boolean = false - - /// Obtaining receiving NIC... - while !gotRecvNIC do - nics(recvNIC).synchronized { - if !nics(recvNIC).assigned then - nics(recvNIC).assigned = true - gotRecvNIC = true - else recvNIC = (recvNIC + 1) % (if limitRecvNICs then n - 1 else n) - } - // Successfully obtained receiving NIC - - // Obtaining sending NIC... - while !gotSendNIC do - nics(sendNIC).synchronized { - if !nics(sendNIC).assigned then - nics(sendNIC).assigned = true - gotSendNIC = true - else sendNIC = (sendNIC + 1) % n - } - // Successfully obtained sending NIC - - return (recvNIC, sendNIC) diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part8.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/Part8.scala deleted file mode 100644 index 008ee0fac9bbe46a709267210feee011a050c524..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/Part8.scala +++ /dev/null @@ -1,85 +0,0 @@ -package midterm - -import scala.collection.concurrent.{TrieMap, Map} -import java.util.concurrent.atomic.AtomicInteger -import scala.annotation.tailrec - -// Question 25 - -// See tests in midterm.Part8Test. -// Run with `sbt "testOnly midterm.Part8Test"`. - -// Represent a social network where user can follow each other. Each user is -// represented by an id that is an `Int`. -abstract class AbstractInstagram: - // The map storing the "following" relation of our social network. - // `graph(a)` contains the list of user ids that user `a` follows. - val graph: Map[Int, List[Int]] = new TrieMap[Int, List[Int]]() - - // The maximum user id allocated until now. This value should be incremented - // by one each time a new user is added. - val maxId = new AtomicInteger(0) - - // Allocates a new user and returns its unique id. Internally, this should - // also create an empty list at the corresponding id in `graph`. The - // implementation must be thread-safe. - def add(): Int - - // Make `a` follow `b`. The implementation must be thread-safe. - def follow(a: Int, b: Int): Unit - - // Makes `a` unfollow `b`. The implementation must be thread-safe. - def unfollow(a: Int, b: Int): Unit - - // Removes user with id `a`. This should also remove all references to `a` - // in `graph`. The implementation must be thread-safe. - def remove(a: Int): Unit - -class Instagram extends AbstractInstagram: - // This method is worth 6 points. - def add(): Int = - // It is important to increment and read the value in one atomic step. See - // test `testParallelWrongAdd` for an alternative wrong implementation. - val id = maxId.incrementAndGet - // Note: it is also correct to use `graph.putIfAbsent`, but not needed as - // `id` is always new and therefore absent from the map at this point. - graph.update(id, Nil) - id - - // This method is worth 8 points. - def remove(a: Int): Unit = - graph.remove(a) - // Iterate through all keys to make sure that nobody follows `a` anymore. - // For each key, we need to unfollow a in a thread-safe manner. Calling - // `unfollow` is the simplest way to so, as it is already guaranteed to be - // thread-safe. See test `testParallelWrongRemove` for an example of wrong - // implementation. - for b <- graph.keys do unfollow(b, a) - - // This method is worth 10 points. - def unfollow(a: Int, b: Int) = - // Here, it is important to read the value only once. First calling - // `.contains(a)` and then `graph(a)` (or `graph.apply(a)`--which is the - // same thing) does not work because `a` might be removed between the two - // calls. See `testParallelWrongUnfollow` for an example of this wrong - // implementation. - val prev = graph.get(a) - // Returns silently if `a` does not exist. - if prev.isEmpty then return - // We replace the list of users that `a` follows in an atomic manner. If the - // list of followed users changed concurrently, we start over. - if !graph.replace(a, prev.get, prev.get.filter(_ != b)) then unfollow(a, b) - - // This method is worth 12 points. - def follow(a: Int, b: Int) = - val prev = graph.get(a) - // Returns silently if `a` does not exist. - if prev.isEmpty then return - // We replace the list of users that `a` follows in an atomic manner. If the - // list of followed users changed concurrently, we start over. - if !graph.replace(a, prev.get, b :: prev.get) then follow(a, b) - // Difficult: this handles the case where `b` is concurrently removed by - // another thread. To detect this case, we must check if `b` still exists - // after we have followed it, and unfollow it if it is not the case. See - // test `testParallelFollowABRemoveB`. This last step is worth 4 points. - else if !graph.contains(b) then unfollow(a, b) diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/common.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/common.scala deleted file mode 100644 index 642a3f4106d82efcc5fd70f23b6872c6442e57ce..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/common.scala +++ /dev/null @@ -1,30 +0,0 @@ -package midterm - -import java.util.concurrent.ForkJoinTask -import java.util.concurrent.RecursiveTask -import java.util.concurrent.ForkJoinWorkerThread -import java.util.concurrent.ForkJoinPool -import java.util.concurrent.atomic.AtomicInteger - -val forkJoinPool = ForkJoinPool() -var parallelismEnabled = true -var tasksCreated: AtomicInteger = AtomicInteger(0) - -def schedule[T](body: => T): ForkJoinTask[T] = - val t = new RecursiveTask[T]: - def compute = body - Thread.currentThread match - case wt: ForkJoinWorkerThread => t.fork() - case _ => forkJoinPool.execute(t) - t - -def task[T](body: => T): ForkJoinTask[T] = - tasksCreated.incrementAndGet - schedule(body) - -def parallel[A, B](op1: => A, op2: => B): (A, B) = - if parallelismEnabled then - val res1 = task { op1 } - val res2 = op2 - (res1.join(), res2) - else (op1, op2) diff --git a/previous-exams/2022-midterm-code/src/main/scala/midterm/instrumentation/Monitor.scala b/previous-exams/2022-midterm-code/src/main/scala/midterm/instrumentation/Monitor.scala deleted file mode 100644 index dfc3a73ff589c962a6f8e8069162af2012a9812c..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/main/scala/midterm/instrumentation/Monitor.scala +++ /dev/null @@ -1,40 +0,0 @@ -package midterm.instrumentation - -class Dummy - -trait Monitor: - given dummy: Dummy = new Dummy - - def wait()(implicit i: Dummy = dummy) = waitDefault() - - def synchronized[T](e: => T)(implicit i: Dummy = dummy) = synchronizedDefault( - e - ) - - def notify()(implicit i: Dummy = dummy) = notifyDefault() - - def notifyAll()(implicit i: Dummy = dummy) = notifyAllDefault() - - private val lock = new AnyRef - - // Can be overridden. - def waitDefault(): Unit = lock.wait() - def synchronizedDefault[T](toExecute: => T): T = lock.synchronized(toExecute) - def notifyDefault(): Unit = lock.notify() - def notifyAllDefault(): Unit = lock.notifyAll() - -trait LockFreeMonitor extends Monitor: - override def waitDefault() = - throw new Exception("Please use lock-free structures and do not use wait()") - override def synchronizedDefault[T](toExecute: => T): T = - throw new Exception( - "Please use lock-free structures and do not use synchronized()" - ) - override def notifyDefault() = - throw new Exception( - "Please use lock-free structures and do not use notify()" - ) - override def notifyAllDefault() = - throw new Exception( - "Please use lock-free structures and do not use notifyAll()" - ) diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Mock2Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Mock2Test.scala deleted file mode 100644 index 4d1fab13a1a6050835de004349ce1e84f2af0e4c..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Mock2Test.scala +++ /dev/null @@ -1,29 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* -import instrumentation.* - -class Mock2Test: - @Test - def test() = - TestUtils.assertDeadlock( - TestHelper.testManySchedules( - 2, - scheduler => - val a = new ScheduledAccount(50, scheduler) - val b = new ScheduledAccount(70, scheduler) - - ( - List( - () => a.transfer(b, 10), - () => b.transfer(a, 10) - ), - results => (true, "") - ) - ) - ) - - class ScheduledAccount(n: Int, val scheduler: Scheduler) - extends Account(n) - with MockedMonitor diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part1Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part1Test.scala deleted file mode 100644 index 8f47c66f99330e02594a3c2104fd14d30c1c44c5..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part1Test.scala +++ /dev/null @@ -1,26 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* - -class Part1Test: - val testArray = - Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) - - @Test - def testQuestion1Pos() = - val tasksCreatedBefore = tasksCreated.get - assertEquals(Some(18), find(testArray, 18, 3)) - assertEquals(10, tasksCreated.get - tasksCreatedBefore) - - @Test - def testQuestion1Neg() = - assertEquals(find(testArray, 20, 3), None) - - @Test - def testQuestion2Pos(): Unit = - assertEquals(findAggregated(testArray, 18), Some(18)) - - @Test - def testQuestion2Neg(): Unit = - assertEquals(findAggregated(testArray, 20), None) diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part2Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part2Test.scala deleted file mode 100644 index 2dda7b5f3e5286dcd17f3437af24deff7916c41b..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part2Test.scala +++ /dev/null @@ -1,24 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* - -class Part2Test: - val testArray2 = Array(0, 50, 7, 1, 28, 42) - val testList2 = List(0, 50, 7, 1, 28, 42) - - @Test - def testQuestion4Pos() = - assert(contains(testArray2, 7)) - - @Test - def testQuestion4Neg() = - assert(!contains(testArray2, 8)) - - @Test - def testQuestion6Pos() = - assert(contains(testList2, 7)) - - @Test - def testQuestion6Neg() = - assert(!contains(testList2, 8)) diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part4Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part4Test.scala deleted file mode 100644 index 1991cb8f02e4237c528fa6e0081b04a997eb6563..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part4Test.scala +++ /dev/null @@ -1,250 +0,0 @@ -package midterm - -import midterm.instrumentation.Monitor -import midterm.instrumentation.MockedMonitor - -import org.junit.* -import org.junit.Assert.* -import instrumentation.* -import java.util.concurrent.atomic.AtomicInteger - -class Part4Test: - - // This test can result in a deadlock because locks can be called in any - // order. Here, Thread 1 locks Node 3 first and then Node 2, whereas Thread 2 - // locks Node 2 first and then Node 3. This will lead to a deadlock. - @Test - def testQuestion9() = - TestUtils.assertDeadlock( - TestHelper.testManySchedules( - 2, - scheduler => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, scheduler)).toList - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = sum += e - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes - lockFun(nodes, increment), - ), - results => (true, "") - ) - ) - ) - - // This will not lead to a deadlock because the lock acquire happens in a - // particular order. Thread 1 acquires locks in order 1->2->3->4, whereas - // Thread 2 acquires locks in order 2->3->5. - @Test - def testQuestion10() = - TestHelper.testManySchedules( - 2, - scheduler => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, scheduler)).toList - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = sum += e - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.sortWith((x, y) => x.guid > y.guid) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.sortWith((x, y) => x.guid > y.guid) - lockFun(nodes, increment), - ), - results => (true, "") - ) - ) - - - // This will not lead to a deadlock because the lock acquire happens in a - // particular order. Thread 1 acquires locks in order 4->3->2->1, whereas - // Thread 2 acquires locks in order 5->3->2. - @Test - def testQuestion11() = - TestHelper.testManySchedules( - 2, - scheduler => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, scheduler)).toList - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = sum += e - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - ), - results => (true, "") - ) - ) - - // This test can result in a deadlock because locks are not called in any - // order. Thread 1 acquire order (3->2->4->1), Thread 2 acquire order - // (2->3->5). Thread 1 locks Node3 first and then Node2, whereas Thread 2 - // locks Node 2 first and then Node3. This will lead to a deadlock. - @Test - def testQuestion12() = - TestUtils.assertDeadlock( - TestHelper.testManySchedules( - 2, - scheduler => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, scheduler)).toList - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = sum += e - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.tail.appended(nodes(0)) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.tail.appended(nodes(0)) - lockFun(nodes, increment), - ), - results => (true, "") - ) - ) - ) - - // sum returns wrong answer because there is a data race on the sum variable. - @Test(expected = classOf[AssertionError]) - def testQuestion13() = - TestHelper.testManySchedules( - 2, - scheduler => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, scheduler)).toList - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = - val previousSum = scheduler.exec{sum}("Get sum") - scheduler.exec{sum = previousSum + e}("Write sum") - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - ), - results => - if sum != 20 then - (false, f"Wrong sum: expected 20 but got $sum") - else - (true, "") - ) - ) - - // sum value will be correct here because "sum += e" is protected by a lock. - @Test - def testQuestion14() = - TestHelper.testManySchedules( - 2, - sched => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, sched)).toList - - val monitor = new MockedMonitor: // Monitor is a type of a lock. - def scheduler = sched - - // Shared by all threads - var sum: Int = 0 - def increment(e: Int) = - monitor.synchronized { sum += e } - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - ), - results => - if sum != 20 then - (false, f"Wrong sum: expected 20 but got $sum") - else - (true, "") - ) - ) - - // total will give correct output here as it is an atomic instruction. - @Test - def testQuestion15() = - TestHelper.testManySchedules( - 2, - sched => - val allNodes = (for i <- 0 to 6 yield ScheduledNode(i, sched)).toList - - // Shared by all threads - var total: AtomicInteger = new AtomicInteger(0) - def increment(e: Int) = - total.addAndGet(e) - - ( - List( - () => - // Thread 1 - var nodes: List[Node] = List(allNodes(1), allNodes(3), allNodes(2), allNodes(4)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - () => - // Thread 2 - var nodes: List[Node] = List(allNodes(5), allNodes(2), allNodes(3)) - nodes = nodes.sortWith((x, y) => x.guid < y.guid) - lockFun(nodes, increment), - ), - results => - if total.get != 20 then - (false, f"Wrong total: expected 20 but got $total") - else - (true, "") - ) - ) - - - class ScheduledNode(value: Int, val scheduler: Scheduler) extends Node(value) with MockedMonitor diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part6Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part6Test.scala deleted file mode 100644 index d6412345fc9bff74fd9a68ad3eeee6137d42a045..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part6Test.scala +++ /dev/null @@ -1,33 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* -import midterm.instrumentation.* - -class Part6Test: - @Test(expected = classOf[AssertionError]) - def testQuestion21() = - TestHelper.testManySchedules( - 2, - scheduler => - val ticketsManager = ScheduledTicketsManager(1, scheduler) - - ( - List( - () => - // Thread 1 - ticketsManager.getTicket(), - () => - // Thread 2 - ticketsManager.getTicket() - ), - results => - if ticketsManager.remainingTickets < 0 then - (false, "Sold more tickets than available!") - else (true, "") - ) - ) - - class ScheduledTicketsManager(totalTickets: Int, val scheduler: Scheduler) - extends TicketsManager(totalTickets) - with MockedMonitor diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part7Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part7Test.scala deleted file mode 100644 index e818585d31ac34b2ac80c9819ed6433d8248229c..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part7Test.scala +++ /dev/null @@ -1,89 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* -import midterm.instrumentation.* - -class Part7Test: - @Test - def testNicManagerSequential() = - val nicsManager = NICManager(4) - assertEquals((0, 1), nicsManager.assignNICs()) - assertEquals((2, 3), nicsManager.assignNICs()) - - @Test - def testQuestion22() = - testNicManagerParallel(2, 3) - - @Test - def testQuestion23() = - val nicsManager = NICManager(2) - - // Thread 1 - assertEquals((0, 1), nicsManager.assignNICs()) - nicsManager.nics(0).assigned = false - nicsManager.nics(1).assigned = false - - // Thread 2 - assertEquals((0, 1), nicsManager.assignNICs()) - nicsManager.nics(0).assigned = false - nicsManager.nics(1).assigned = false - - @Test - def testQuestion24() = - testNicManagerParallel(3, 2, true) - - @Test - def testQuestion24NotLimitingRecvNICs() = - TestUtils.assertMaybeDeadlock( - testNicManagerParallel(3, 2) - ) - - def testNicManagerParallel( - threads: Int, - nics: Int, - limitRecvNICs: Boolean = false - ) = - TestHelper.testManySchedules( - threads, - scheduler => - val nicsManager = ScheduledNicsManager(nics, scheduler) - val tasks = for i <- 0 until threads yield () => - // Thread i - val (recvNIC, sendNIC) = nicsManager.assignNICs(limitRecvNICs) - - // Do something with NICs... - - // Un-assign NICs - nicsManager.nics(recvNIC).assigned = false - nicsManager.nics(sendNIC).assigned = false - ( - tasks.toList, - results => - if nicsManager.nics.count(_.assigned) != 0 then - (false, f"All NICs should have been released.") - else (true, "") - ) - ) - - class ScheduledNicsManager(n: Int, scheduler: Scheduler) - extends NICManager(n): - class ScheduledNIC( - _index: Int, - _assigned: Boolean, - val scheduler: Scheduler - ) extends NIC(_index, _assigned) - with MockedMonitor: - override def index = scheduler.exec { super.index }( - "", - Some(res => f"read NIC.index == $res") - ) - override def assigned = scheduler.exec { super.assigned }( - "", - Some(res => f"read NIC.assigned == $res") - ) - override def assigned_=(v: Boolean) = scheduler.exec { super.assigned = v }( - f"write NIC.assigned = $v" - ) - override val nics = - (for i <- 0 until n yield ScheduledNIC(i, false, scheduler)).toList diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part8Test.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/Part8Test.scala deleted file mode 100644 index 6d5a50a6bf7053f1a02720e8500f7923ca1a30fb..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/Part8Test.scala +++ /dev/null @@ -1,378 +0,0 @@ -package midterm - -import org.junit.* -import org.junit.Assert.* -import instrumentation.* - -import scala.collection.concurrent.TrieMap -import scala.collection.concurrent.{TrieMap, Map} - -class Part8Test: - @Test - def usage() = - val insta = Instagram() - assertEquals(1, insta.add()) - assertEquals(2, insta.add()) - insta.follow(1, 2) - assertEquals(insta.graph, Map(1 -> List(2), 2 -> List())) - insta.follow(2, 1) - insta.unfollow(1, 2) - assertEquals(insta.graph, Map(1 -> List(), 2 -> List(1))) - insta.follow(3, 1) // fails silently - assertEquals(insta.graph, Map(1 -> List(), 2 -> List(1))) - insta.remove(1) - assertEquals(insta.graph, Map(2 -> List())) - insta.unfollow(1, 2) // fails silently - - @Test - def testParallelFollowABRemoveA() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - val u1 = insta.add() - val u2 = insta.add() - - ( - List( - () => - // Thread 1 - insta.follow(u1, u2), - () => - // Thread 2 - insta.remove(u1) - ), - results => - val size = insta.graph.size - if size != 1 then - (false, f"Wrong number of user: expected 1 but got ${size}") - else validateGraph(insta) - ) - ) - - @Test - def testParallelFollowABRemoveB() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - val u1 = insta.add() - val u2 = insta.add() - - ( - List( - () => - // Thread 1 - insta.follow(u1, u2), - () => - // Thread 2 - insta.remove(u2) - ), - results => - val size = insta.graph.size - if size != 1 then - (false, f"Wrong number of user: expected 1 but got ${size}") - else validateGraph(insta) - ) - ) - - @Test - def testParallelFollowACRemoveB() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - val u1 = insta.add() - val u2 = insta.add() - val u3 = insta.add() - insta.follow(u1, u2) - - ( - List( - () => - // Thread 1 - insta.follow(u1, u3), - () => - // Thread 2 - insta.remove(u2) - ), - results => - val size = insta.graph.size - if size != 2 then - (false, f"Wrong number of user: expected 2 but got ${size}") - else validateGraph(insta) - ) - ) - - @Test - def testParallelFollow() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - val u1 = insta.add() - val u2 = insta.add() - val u3 = insta.add() - - ( - List( - () => - // Thread 1 - insta.follow(u1, u2), - () => - // Thread 2 - insta.follow(u1, u3) - ), - results => - val u1FollowingSize = insta.graph(u1).size - if u1FollowingSize != 2 then - ( - false, - f"Wrong number of users followed by user 1: expected 2 but got ${u1FollowingSize}" - ) - else validateGraph(insta) - ) - ) - - @Test - def testParallelRemove() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - // Setup - val u1 = insta.add() - val u2 = insta.add() - val u3 = insta.add() - insta.follow(u1, u2) - insta.follow(u2, u1) - insta.follow(u2, u3) - insta.follow(u3, u1) - - ( - List( - () => - // Thread 1 - insta.remove(u2), - () => - // Thread 2 - insta.remove(u3) - ), - results => - val size = insta.graph.size - if size != 1 then - (false, f"Wrong number of user: expected 1 but got ${size}") - else validateGraph(insta) - ) - ) - - // We test wrong code here, so we expect an assertion error. You can replace - // the next line by `@Test` if you want to see the error with the failing - // schedule. - @Test(expected = classOf[AssertionError]) - def testParallelWrongAdd() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - // This implementation of `add` is wrong, because two threads might - // allocate the same id. - // Consider the following schedule: - // T1: res = 1 - // T2: res = 2 - // T2: graph.update(2, Nil) - // T2: 2 - // T1: graph.update(2, Nil) - // T1: 2 - override def add(): Int = - val res = maxId.incrementAndGet - graph.update(maxId.get, Nil) - res - - ( - List( - () => - // Thread 1 - insta.add(), - () => - // Thread 2 - insta.add() - ), - results => - if results(0) != results(1) then - (false, f"Allocated twice id ${results(0)}") - else validateGraph(insta) - ) - ) - - // We test wrong code here, so we expect an assertion error. You can replace - // the next line by `@Test` if you want to see the error with the failing - // schedule. - @Test(expected = classOf[AssertionError]) - def testParallelWrongRemove() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - - // This implementation of `remove` is wrong because we don't retry to - // call `graph.replace` when it fails. Therefore, user 1 might end up - // following user 2 that has been removed, or not following user 3 - // which is concurrently followed. - override def remove(idToRemove: Int): Unit = - graph.remove(idToRemove) - for (key, value) <- graph do - graph.replace(key, value, value.filter(_ != idToRemove)) - // Note: writing `graph(key) = value.filter(_ != idToRemove)` - // would also be wrong because it does not check the previous - // value. Therefore, it could erase a concurrent update. - - val u1 = insta.add() - val u2 = insta.add() - val u3 = insta.add() - insta.follow(u1, u2) - - ( - List( - () => - // Thread 1 - insta.follow(u1, u3), - () => - // Thread 2 - insta.remove(u2) - ), - results => - val size = insta.graph.size - if insta.graph(u1).size != 1 then - (false, f"Wrong number of users followed by 1: expected 1 but got ${insta.graph(u1)}") - else validateGraph(insta) - ) - ) - - // We test wrong code here, so we expect an assertion error. You can replace - // the next line by `@Test` if you want to see the error with the failing - // schedule. - @Test(expected = classOf[AssertionError]) - def testParallelWrongUnfollow() = - TestHelper.testManySchedules( - 2, - scheduler => - val insta = new Instagram: - override val graph = - ScheduledTrieMap(TrieMap[Int, List[Int]](), scheduler) - override def unfollow(a: Int, b: Int): Unit = - if !graph.contains(a) then return - val prev = graph(a) // Might throw java.util.NoSuchElementException - if !graph.replace(a, prev, prev.filter(_ != b)) then unfollow(a, b) - - val u1 = insta.add() - val u2 = insta.add() - insta.follow(u1, u2) - - ( - List( - () => - // Thread 1 - insta.unfollow(u1, u2), - () => - // Thread 2 - insta.remove(u1) - ), - results => - val size = insta.graph.size - if size != 1 then - (false, f"Wrong number of user: expected 1 but got ${size}") - else validateGraph(insta) - ) - ) - - def validateGraph(insta: Instagram): (Boolean, String) = - for (a, following) <- insta.graph; b <- following do - if !insta.graph.contains(b) then - return (false, f"User $a follows non-existing user $b") - (true, "") - - final class ScheduledIterator[T]( - private val myIterator: Iterator[T], - private val scheduler: Scheduler - ) extends Iterator[T]: - override def hasNext = - myIterator.hasNext - override def next() = - scheduler.exec(myIterator.next)("", Some(res => f"Iterator.next == $res")) - override def knownSize: Int = - myIterator.knownSize - - final class ScheduledTrieMap[K, V]( - private val myMap: Map[K, V], - private val scheduler: Scheduler - ) extends Map[K, V]: - override def apply(key: K): V = - scheduler.exec(myMap(key))( - "", - Some(res => f"TrieMap.apply($key) == $res") - ) - override def contains(key: K): Boolean = - scheduler.exec(myMap.contains(key))( - "", - Some(res => f"TrieMap.contains($key) == $res") - ) - override def get(key: K): Option[V] = - scheduler.exec(myMap.get(key))( - "", - Some(res => f"TrieMap.get($key) == $res") - ) - override def addOne(kv: (K, V)) = - scheduler.exec(myMap.addOne(kv))(f"TrieMap.addOne($kv)") - this - override def subtractOne(k: K) = - scheduler.exec(myMap.subtractOne(k))(f"TrieMap.subtractOne($k)") - this - override def iterator() = - scheduler.log("TrieMap.iterator") - ScheduledIterator(myMap.iterator, scheduler) - override def replace(k: K, v: V): Option[V] = - scheduler.exec(myMap.replace(k, v))( - "", - Some(res => f"TrieMap.replace($k, $v) == $res") - ) - override def replace(k: K, oldvalue: V, newvalue: V): Boolean = - scheduler.exec(myMap.replace(k, oldvalue, newvalue))( - "", - Some(res => f"TrieMap.replace($k, $oldvalue, $newvalue) == $res") - ) - override def putIfAbsent(k: K, v: V): Option[V] = - scheduler.exec(myMap.putIfAbsent(k, v))( - "", - Some(res => f"TrieMap.putIfAbsent($k, $v)") - ) - override def remove(k: K): Option[V] = - scheduler.exec(myMap.remove(k))( - "", - Some(res => f"TrieMap.remove($k)") - ) - override def remove(k: K, v: V): Boolean = - scheduler.exec(myMap.remove(k, v))( - "", - Some(res => f"TrieMap.remove($k, $v)") - ) diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/MockedMonitor.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/MockedMonitor.scala deleted file mode 100644 index 341d8feb7fc6e9978987e0440a7dfe30c8b7a7b3..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/MockedMonitor.scala +++ /dev/null @@ -1,46 +0,0 @@ -package midterm.instrumentation - -trait MockedMonitor extends Monitor: - def scheduler: Scheduler - - // Can be overriden. - override def waitDefault() = - scheduler.log("wait") - scheduler updateThreadState Wait(this, scheduler.threadLocks.tail) - override def synchronizedDefault[T](toExecute: =>T): T = - scheduler.log("synchronized check") - val prevLocks = scheduler.threadLocks - scheduler updateThreadState Sync(this, prevLocks) // If this belongs to prevLocks, should just continue. - scheduler.log("synchronized -> enter") - try - toExecute - finally - scheduler updateThreadState Running(prevLocks) - scheduler.log("synchronized -> out") - override def notifyDefault() = - scheduler mapOtherStates { - state => state match - case Wait(lockToAquire, locks) if lockToAquire == this => SyncUnique(this, state.locks) - case e => e - } - scheduler.log("notify") - override def notifyAllDefault() = - scheduler mapOtherStates { - state => state match - case Wait(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case SyncUnique(lockToAquire, locks) if lockToAquire == this => Sync(this, state.locks) - case e => e - } - scheduler.log("notifyAll") - -abstract class ThreadState: - def locks: Seq[AnyRef] -trait CanContinueIfAcquiresLock extends ThreadState: - def lockToAquire: AnyRef -case object Start extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case object End extends ThreadState { def locks: Seq[AnyRef] = Seq.empty } -case class Wait(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState -case class SyncUnique(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Sync(lockToAquire: AnyRef, locks: Seq[AnyRef]) extends ThreadState with CanContinueIfAcquiresLock -case class Running(locks: Seq[AnyRef]) extends ThreadState -case class VariableReadWrite(locks: Seq[AnyRef]) extends ThreadState diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Scheduler.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Scheduler.scala deleted file mode 100644 index 8c26437f9f6a56a8c3b78e45a1ab6398c78c0868..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Scheduler.scala +++ /dev/null @@ -1,276 +0,0 @@ -package midterm.instrumentation - -import java.util.concurrent._; -import scala.concurrent.duration._ -import scala.collection.mutable._ -import Stats._ - -import java.util.concurrent.atomic.AtomicInteger - -sealed abstract class Result -case class RetVal(rets: List[Any]) extends Result -case class Except(msg: String, stackTrace: Array[StackTraceElement]) extends Result -case class Timeout(msg: String) extends Result - -/** - * A class that maintains schedule and a set of thread ids. - * The schedules are advanced after an operation of a SchedulableBuffer is performed. - * Note: the real schedule that is executed may deviate from the input schedule - * due to the adjustments that had to be made for locks - */ -class Scheduler(sched: List[Int]): - val maxOps = 500 // a limit on the maximum number of operations the code is allowed to perform - - private var schedule = sched - private var numThreads = 0 - private val realToFakeThreadId = Map[Long, Int]() - private val opLog = ListBuffer[String]() // a mutable list (used for efficient concat) - private val threadStates = Map[Int, ThreadState]() - - /** - * Runs a set of operations in parallel as per the schedule. - * Each operation may consist of many primitive operations like reads or writes - * to shared data structure each of which should be executed using the function `exec`. - * @timeout in milliseconds - * @return true - all threads completed on time, false -some tests timed out. - */ - def runInParallel(timeout: Long, ops: List[() => Any]): Result = - numThreads = ops.length - val threadRes = Array.fill(numThreads) { None: Any } - var exception: Option[Except] = None - val syncObject = new Object() - var completed = new AtomicInteger(0) - // create threads - val threads = ops.zipWithIndex.map { - case (op, i) => - new Thread(new Runnable() { - def run(): Unit = { - val fakeId = i + 1 - setThreadId(fakeId) - try { - updateThreadState(Start) - val res = op() - updateThreadState(End) - threadRes(i) = res - // notify the main thread if all threads have completed - if completed.incrementAndGet() == ops.length then { - syncObject.synchronized { syncObject.notifyAll() } - } - } catch { - case e: Throwable if exception != None => // do nothing here and silently fail - case e: Throwable => - log(s"throw ${e.toString}") - exception = Some(Except(s"Thread $fakeId crashed on the following schedule: \n" + opLog.mkString("\n"), - e.getStackTrace)) - syncObject.synchronized { syncObject.notifyAll() } - //println(s"$fakeId: ${e.toString}") - //Runtime.getRuntime().halt(0) //exit the JVM and all running threads (no other way to kill other threads) - } - } - }) - } - // start all threads - threads.foreach(_.start()) - // wait for all threads to complete, or for an exception to be thrown, or for the time out to expire - var remTime = timeout - syncObject.synchronized { - timed { if completed.get() != ops.length then syncObject.wait(timeout) } { time => remTime -= time } - } - if exception.isDefined then - exception.get - else if remTime <= 1 then // timeout ? using 1 instead of zero to allow for some errors - Timeout(opLog.mkString("\n")) - else - // every thing executed normally - RetVal(threadRes.toList) - - // Updates the state of the current thread - def updateThreadState(state: ThreadState): Unit = - val tid = threadId - synchronized { - threadStates(tid) = state - } - state match - case Sync(lockToAquire, locks) => - if locks.indexOf(lockToAquire) < 0 then waitForTurn else - // Re-aqcuiring the same lock - updateThreadState(Running(lockToAquire +: locks)) - case Start => waitStart() - case End => removeFromSchedule(tid) - case Running(_) => - case _ => waitForTurn // Wait, SyncUnique, VariableReadWrite - - def waitStart(): Unit = - //while (threadStates.size < numThreads) { - //Thread.sleep(1) - //} - synchronized { - if threadStates.size < numThreads then - wait() - else - notifyAll() - } - - def threadLocks = - synchronized { - threadStates(threadId).locks - } - - def threadState = - synchronized { - threadStates(threadId) - } - - def mapOtherStates(f: ThreadState => ThreadState) = - val exception = threadId - synchronized { - for k <- threadStates.keys if k != exception do - threadStates(k) = f(threadStates(k)) - } - - def log(str: String) = - if (realToFakeThreadId contains Thread.currentThread().getId()) then - val space = (" " * ((threadId - 1) * 2)) - val s = space + threadId + ":" + "\n".r.replaceAllIn(str, "\n" + space + " ") - //println(s) - opLog += s - - /** - * Executes a read or write operation to a global data structure as per the given schedule - * @param msg a message corresponding to the operation that will be logged - */ - def exec[T](primop: => T)(msg: => String, postMsg: => Option[T => String] = None): T = - if ! (realToFakeThreadId contains Thread.currentThread().getId()) then - primop - else - updateThreadState(VariableReadWrite(threadLocks)) - val m = msg - if m != "" then log(m) - if opLog.size > maxOps then - throw new Exception(s"Total number of reads/writes performed by threads exceed $maxOps. A possible deadlock!") - val res = primop - postMsg match - case Some(m) => log(m(res)) - case None => - res - - private def setThreadId(fakeId: Int) = synchronized { - realToFakeThreadId(Thread.currentThread.getId) = fakeId - } - - def threadId = - try - realToFakeThreadId(Thread.currentThread().getId()) - catch - case e: NoSuchElementException => - throw new Exception("You are accessing shared variables in the constructor. This is not allowed. The variables are already initialized!") - - private def isTurn(tid: Int) = synchronized { - (!schedule.isEmpty && schedule.head != tid) - } - - def canProceed(): Boolean = - val tid = threadId - canContinue match - case Some((i, state)) if i == tid => - //println(s"$tid: Runs ! Was in state $state") - canContinue = None - state match - case Sync(lockToAquire, locks) => updateThreadState(Running(lockToAquire +: locks)) - case SyncUnique(lockToAquire, locks) => - mapOtherStates { - _ match - case SyncUnique(lockToAquire2, locks2) if lockToAquire2 == lockToAquire => Wait(lockToAquire2, locks2) - case e => e - } - updateThreadState(Running(lockToAquire +: locks)) - case VariableReadWrite(locks) => updateThreadState(Running(locks)) - true - case Some((i, state)) => - //println(s"$tid: not my turn but $i !") - false - case None => - false - - var threadPreference = 0 // In the case the schedule is over, which thread should have the preference to execute. - - /** returns true if the thread can continue to execute, and false otherwise */ - def decide(): Option[(Int, ThreadState)] = - if !threadStates.isEmpty then // The last thread who enters the decision loop takes the decision. - //println(s"$threadId: I'm taking a decision") - if threadStates.values.forall { case e: Wait => true case _ => false } then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - throw new Exception(s"Deadlock: Thread$s $waiting $are waiting but all others have ended and cannot notify them.") - else - // Threads can be in Wait, Sync, SyncUnique, and VariableReadWrite mode. - // Let's determine which ones can continue. - val notFree = threadStates.collect { case (id, state) => state.locks }.flatten.toSet - val threadsNotBlocked = threadStates.toSeq.filter { - case (id, v: VariableReadWrite) => true - case (id, v: CanContinueIfAcquiresLock) => !notFree(v.lockToAquire) || (v.locks contains v.lockToAquire) - case _ => false - } - if threadsNotBlocked.isEmpty then - val waiting = threadStates.keys.map(_.toString).mkString(", ") - val s = if threadStates.size > 1 then "s" else "" - val are = if threadStates.size > 1 then "are" else "is" - val whoHasLock = threadStates.toSeq.flatMap { case (id, state) => state.locks.map(lock => (lock, id)) }.toMap - val reason = threadStates.collect { - case (id, state: CanContinueIfAcquiresLock) if !notFree(state.lockToAquire) => - s"Thread $id is waiting on lock ${state.lockToAquire} held by thread ${whoHasLock(state.lockToAquire)}" - }.mkString("\n") - throw new Exception(s"Deadlock: Thread$s $waiting are interlocked. Indeed:\n$reason") - else if threadsNotBlocked.size == 1 then // Do not consume the schedule if only one thread can execute. - Some(threadsNotBlocked(0)) - else - val next = schedule.indexWhere(t => threadsNotBlocked.exists { case (id, state) => id == t }) - if next != -1 then - //println(s"$threadId: schedule is $schedule, next chosen is ${schedule(next)}") - val chosenOne = schedule(next) // TODO: Make schedule a mutable list. - schedule = schedule.take(next) ++ schedule.drop(next + 1) - Some((chosenOne, threadStates(chosenOne))) - else - threadPreference = (threadPreference + 1) % threadsNotBlocked.size - val chosenOne = threadsNotBlocked(threadPreference) // Maybe another strategy - Some(chosenOne) - //threadsNotBlocked.indexOf(threadId) >= 0 - /* - val tnb = threadsNotBlocked.map(_._1).mkString(",") - val s = if (schedule.isEmpty) "empty" else schedule.mkString(",") - val only = if (schedule.isEmpty) "" else " only" - throw new Exception(s"The schedule is $s but$only threads ${tnb} can continue")*/ - else canContinue - - /** - * This will be called before a schedulable operation begins. - * This should not use synchronized - */ - var numThreadsWaiting = new AtomicInteger(0) - //var waitingForDecision = Map[Int, Option[Int]]() // Mapping from thread ids to a number indicating who is going to make the choice. - var canContinue: Option[(Int, ThreadState)] = None // The result of the decision thread Id of the thread authorized to continue. - private def waitForTurn = - synchronized { - if numThreadsWaiting.incrementAndGet() == threadStates.size then - canContinue = decide() - notifyAll() - //waitingForDecision(threadId) = Some(numThreadsWaiting) - //println(s"$threadId Entering waiting with ticket number $numThreadsWaiting/${waitingForDecision.size}") - while !canProceed() do wait() - } - numThreadsWaiting.decrementAndGet() - - /** - * To be invoked when a thread is about to complete - */ - private def removeFromSchedule(fakeid: Int) = synchronized { - //println(s"$fakeid: I'm taking a decision because I finished") - schedule = schedule.filterNot(_ == fakeid) - threadStates -= fakeid - if numThreadsWaiting.get() == threadStates.size then - canContinue = decide() - notifyAll() - } - - def getOperationLog() = opLog diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Stats.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Stats.scala deleted file mode 100644 index 2d6d76dd63ce507a6b14db597fad6fa74b9259ff..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/Stats.scala +++ /dev/null @@ -1,19 +0,0 @@ -package midterm.instrumentation - -import java.lang.management._ - -/** - * A collection of methods that can be used to collect run-time statistics about Leon programs. - * This is mostly used to test the resources properties of Leon programs - */ -object Stats: - def timed[T](code: => T)(cont: Long => Unit): T = - var t1 = System.currentTimeMillis() - val r = code - cont((System.currentTimeMillis() - t1)) - r - - def withTime[T](code: => T): (T, Long) = - var t1 = System.currentTimeMillis() - val r = code - (r, (System.currentTimeMillis() - t1)) diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestHelper.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestHelper.scala deleted file mode 100644 index 5bd22dd29410415b02120f1346937b67d523839d..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestHelper.scala +++ /dev/null @@ -1,112 +0,0 @@ -package midterm.instrumentation - -import scala.util.Random -import scala.collection.mutable.{Map => MutableMap} - -import Stats._ - -object TestHelper: - val noOfSchedules = 10000 // set this to 100k during deployment - val readWritesPerThread = 20 // maximum number of read/writes possible in one thread - val contextSwitchBound = 10 - val testTimeout = 240 // the total time out for a test in seconds - val schedTimeout = 15 // the total time out for execution of a schedule in secs - - // Helpers - /*def testManySchedules(op1: => Any): Unit = testManySchedules(List(() => op1)) - def testManySchedules(op1: => Any, op2: => Any): Unit = testManySchedules(List(() => op1, () => op2)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3)) - def testManySchedules(op1: => Any, op2: => Any, op3: => Any, op4: => Any): Unit = testManySchedules(List(() => op1, () => op2, () => op3, () => op4))*/ - - def testSequential[T](ops: Scheduler => Any)(assertions: T => (Boolean, String)) = - testManySchedules(1, - (sched: Scheduler) => { - (List(() => ops(sched)), - (res: List[Any]) => assertions(res.head.asInstanceOf[T])) - }) - - /** - * @numThreads number of threads - * @ops operations to be executed, one per thread - * @assertion as condition that will executed after all threads have completed (without exceptions) - * the arguments are the results of the threads - */ - def testManySchedules(numThreads: Int, - ops: Scheduler => - (List[() => Any], // Threads - List[Any] => (Boolean, String)) // Assertion - ) = - var timeout = testTimeout * 1000L - val threadIds = (1 to numThreads) - //(1 to scheduleLength).flatMap(_ => threadIds).toList.permutations.take(noOfSchedules).foreach { - val schedules = (new ScheduleGenerator(numThreads)).schedules() - var schedsExplored = 0 - schedules.takeWhile(_ => schedsExplored <= noOfSchedules && timeout > 0).foreach { - //case _ if timeout <= 0 => // break - case schedule => - schedsExplored += 1 - val schedr = new Scheduler(schedule) - //println("Exploring Sched: "+schedule) - val (threadOps, assertion) = ops(schedr) - if threadOps.size != numThreads then - throw new IllegalStateException(s"Number of threads: $numThreads, do not match operations of threads: $threadOps") - timed { schedr.runInParallel(schedTimeout * 1000, threadOps) } { t => timeout -= t } match - case Timeout(msg) => - throw new java.lang.AssertionError("assertion failed\n"+"The schedule took too long to complete. A possible deadlock! \n"+msg) - case Except(msg, stkTrace) => - val traceStr = "Thread Stack trace: \n"+stkTrace.map(" at "+_.toString).mkString("\n") - throw new java.lang.AssertionError("assertion failed\n"+msg+"\n"+traceStr) - case RetVal(threadRes) => - // check the assertion - val (success, custom_msg) = assertion(threadRes) - if !success then - val msg = "The following schedule resulted in wrong results: \n" + custom_msg + "\n" + schedr.getOperationLog().mkString("\n") - throw new java.lang.AssertionError("Assertion failed: "+msg) - } - if timeout <= 0 then - throw new java.lang.AssertionError("Test took too long to complete! Cannot check all schedules as your code is too slow!") - - /** - * A schedule generator that is based on the context bound - */ - class ScheduleGenerator(numThreads: Int): - val scheduleLength = readWritesPerThread * numThreads - val rands = (1 to scheduleLength).map(i => new Random(0xcafe * i)) // random numbers for choosing a thread at each position - def schedules(): LazyList[List[Int]] = - var contextSwitches = 0 - var contexts = List[Int]() // a stack of thread ids in the order of context-switches - val remainingOps = MutableMap[Int, Int]() - remainingOps ++= (1 to numThreads).map(i => (i, readWritesPerThread)) // num ops remaining in each thread - val liveThreads = (1 to numThreads).toSeq.toBuffer - - /** - * Updates remainingOps and liveThreads once a thread is chosen for a position in the schedule - */ - def updateState(tid: Int): Unit = - val remOps = remainingOps(tid) - if remOps == 0 then - liveThreads -= tid - else - remainingOps += (tid -> (remOps - 1)) - val schedule = rands.foldLeft(List[Int]()) { - case (acc, r) if contextSwitches < contextSwitchBound => - val tid = liveThreads(r.nextInt(liveThreads.size)) - contexts match - case prev :: tail if prev != tid => // we have a new context switch here - contexts +:= tid - contextSwitches += 1 - case prev :: tail => - case _ => // init case - contexts +:= tid - updateState(tid) - acc :+ tid - case (acc, _) => // here context-bound has been reached so complete the schedule without any more context switches - if !contexts.isEmpty then - contexts = contexts.dropWhile(remainingOps(_) == 0) - val tid = contexts match - case top :: tail => top - case _ => liveThreads(0) // here, there has to be threads that have not even started - updateState(tid) - acc :+ tid - } - schedule #:: schedules() diff --git a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestUtils.scala b/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestUtils.scala deleted file mode 100644 index 6417d5c1f4e05a8f138d1d9aafc5bdc312c1000e..0000000000000000000000000000000000000000 --- a/previous-exams/2022-midterm-code/src/test/scala/midterm/instrumentation/TestUtils.scala +++ /dev/null @@ -1,33 +0,0 @@ -package midterm.instrumentation - -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.concurrent.ExecutionContext.Implicits.global -import org.junit.Assert.* - -object TestUtils: - def failsOrTimesOut[T](action: => T): Boolean = - val asyncAction = Future { - action - } - try - Await.result(asyncAction, 2000.millisecond) - catch - case _: Throwable => return true - return false - - def assertDeadlock[T](action: => T): Unit = - try - action - throw new AssertionError("No error detected.") - catch - case e: AssertionError => - assert(e.getMessage.contains("Deadlock"), "No deadlock detected.") - - def assertMaybeDeadlock[T](action: => T): Unit = - try - action - throw new AssertionError("No error detected.") - catch - case e: AssertionError => - assert(e.getMessage.contains("A possible deadlock!"), "No deadlock detected.") diff --git a/previous-exams/2022-midterm-solutions.pdf b/previous-exams/2022-midterm-solutions.pdf deleted file mode 100644 index f2f66ce13686cd9a68bde8cb76d4b1e416a944cd..0000000000000000000000000000000000000000 Binary files a/previous-exams/2022-midterm-solutions.pdf and /dev/null differ diff --git a/previous-exams/2022-midterm.pdf b/previous-exams/2022-midterm.pdf deleted file mode 100644 index b8de1de8dc42b407d59c9ab5a49b4a383aed851d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2022-midterm.pdf and /dev/null differ diff --git a/slides/CS206 Intro.pdf b/slides/CS206 Intro.pdf deleted file mode 100644 index 87f842c06f178c250e1f5b1f80ec9598aa05f3ff..0000000000000000000000000000000000000000 Binary files a/slides/CS206 Intro.pdf and /dev/null differ diff --git a/slides/week01-parallelism-1.pdf b/slides/week01-parallelism-1.pdf deleted file mode 100644 index 56e4442b6eb4cc788ea3676132109123bb59fc1b..0000000000000000000000000000000000000000 Binary files a/slides/week01-parallelism-1.pdf and /dev/null differ diff --git a/slides/week02-parallelism-2.pdf b/slides/week02-parallelism-2.pdf deleted file mode 100644 index ec63745c1edbdeedb6ec9c8ef0fdf7695ccd6968..0000000000000000000000000000000000000000 Binary files a/slides/week02-parallelism-2.pdf and /dev/null differ diff --git a/slides/week03-parallelism-3.pdf b/slides/week03-parallelism-3.pdf deleted file mode 100644 index 7aa5015469bdf8e24c57d95e7b43413441040566..0000000000000000000000000000000000000000 Binary files a/slides/week03-parallelism-3.pdf and /dev/null differ diff --git a/slides/week04-parallelism-4.pdf b/slides/week04-parallelism-4.pdf deleted file mode 100644 index c110144f6c75672831a5db8056bc392c58145a03..0000000000000000000000000000000000000000 Binary files a/slides/week04-parallelism-4.pdf and /dev/null differ diff --git a/slides/week05-concurrency-1.pdf b/slides/week05-concurrency-1.pdf deleted file mode 100644 index 88f77655c74c85cb03c79b29dd543b2243a90fd5..0000000000000000000000000000000000000000 Binary files a/slides/week05-concurrency-1.pdf and /dev/null differ diff --git a/slides/week06-concurrency-2.pdf b/slides/week06-concurrency-2.pdf deleted file mode 100644 index 0bc4e0a10c5952a1242ccc99caa56bf722dae682..0000000000000000000000000000000000000000 Binary files a/slides/week06-concurrency-2.pdf and /dev/null differ diff --git a/slides/week07-concurrency-3.pdf b/slides/week07-concurrency-3.pdf deleted file mode 100644 index 2cad47304cae0db19979c1b0b34fb26ab2d6c2ce..0000000000000000000000000000000000000000 Binary files a/slides/week07-concurrency-3.pdf and /dev/null differ diff --git a/slides/week08-concurrency-4.pdf b/slides/week08-concurrency-4.pdf deleted file mode 100644 index 8129a23f42fb7e223a2920fddf5284ed3aeb882b..0000000000000000000000000000000000000000 Binary files a/slides/week08-concurrency-4.pdf and /dev/null differ diff --git a/slides/week10-futures-1.pdf b/slides/week10-futures-1.pdf deleted file mode 100644 index 109217cfd67fe58b29c3a08bc894234e611ba40f..0000000000000000000000000000000000000000 Binary files a/slides/week10-futures-1.pdf and /dev/null differ diff --git a/slides/week11-actors-1.pdf b/slides/week11-actors-1.pdf deleted file mode 100755 index a406368c9faa165579b4c9333b093210472c9e3e..0000000000000000000000000000000000000000 Binary files a/slides/week11-actors-1.pdf and /dev/null differ diff --git a/slides/week11-actors-2.pdf b/slides/week11-actors-2.pdf deleted file mode 100755 index 89aa761abf5baaa879c1a4c203066b696df24ee1..0000000000000000000000000000000000000000 Binary files a/slides/week11-actors-2.pdf and /dev/null differ diff --git a/slides/week11-actors-3.pdf b/slides/week11-actors-3.pdf deleted file mode 100755 index 7a4561a967fa0d9058d50de88df4de0076d0e030..0000000000000000000000000000000000000000 Binary files a/slides/week11-actors-3.pdf and /dev/null differ diff --git a/slides/week11-actors-4.pdf b/slides/week11-actors-4.pdf deleted file mode 100644 index 064f9205289831f7e61953fe401d12e42f3ad61d..0000000000000000000000000000000000000000 Binary files a/slides/week11-actors-4.pdf and /dev/null differ diff --git a/slides/week11-actors-5.pdf b/slides/week11-actors-5.pdf deleted file mode 100644 index 651cba9317e505d860f6a1fddc10b0b6aa0c1217..0000000000000000000000000000000000000000 Binary files a/slides/week11-actors-5.pdf and /dev/null differ diff --git a/slides/week12-actors-1.pdf b/slides/week12-actors-1.pdf deleted file mode 100755 index 0c488afa3891470c5b6ec43127a98a299b623c6d..0000000000000000000000000000000000000000 Binary files a/slides/week12-actors-1.pdf and /dev/null differ diff --git a/slides/week12-actors-2.pdf b/slides/week12-actors-2.pdf deleted file mode 100755 index 9cf726a40173076e3affa6db4ad002bb6246aaaf..0000000000000000000000000000000000000000 Binary files a/slides/week12-actors-2.pdf and /dev/null differ diff --git a/slides/week12-actors-3.pdf b/slides/week12-actors-3.pdf deleted file mode 100755 index 1593c920839f970ed23858861f76af0aa174ed17..0000000000000000000000000000000000000000 Binary files a/slides/week12-actors-3.pdf and /dev/null differ diff --git a/slides/week13-actors-1.pdf b/slides/week13-actors-1.pdf deleted file mode 100644 index e820e1109c638352d9232171078df96f02455ff6..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-1.pdf and /dev/null differ diff --git a/slides/week13-actors-2.pdf b/slides/week13-actors-2.pdf deleted file mode 100644 index 837dda7f86e5b842a23cb44b6172309841ce6c0a..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-2.pdf and /dev/null differ diff --git a/slides/week13-actors-3.pdf b/slides/week13-actors-3.pdf deleted file mode 100644 index efb495fe4eadb0945fd500eb08f553a95107c4fc..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-3.pdf and /dev/null differ diff --git a/slides/week13-actors-4.pdf b/slides/week13-actors-4.pdf deleted file mode 100755 index 12357763025987a3797b62dcff1f3365a59aa8e0..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-4.pdf and /dev/null differ diff --git a/slides/week13-actors-5.pdf b/slides/week13-actors-5.pdf deleted file mode 100755 index 87773461624f503e2c47e2f2ffdfe39d6141b8bd..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-5.pdf and /dev/null differ diff --git a/slides/week13-actors-6.pdf b/slides/week13-actors-6.pdf deleted file mode 100644 index de16b3a1824a888a3f9c402403a3fe8a69d01dbc..0000000000000000000000000000000000000000 Binary files a/slides/week13-actors-6.pdf and /dev/null differ