From 35121f867683be92ef5b59cae4d53316cb7df499 Mon Sep 17 00:00:00 2001 From: Alexandre Dubray Date: Mon, 4 Jan 2021 11:27:54 +0100 Subject: [PATCH] Add quizz2 to the exercises --- ObservableAccount/feedback_settings.yaml | 5 + .../public/ObservableAccount.java | 68 ++++++++ ObservableAccount/run | 22 +++ ObservableAccount/src/InginiousTests.java | 86 ++++++++++ ObservableAccount/src/StudentTestRunner.java | 48 ++++++ ObservableAccount/task.yaml | 105 +++++++++++++ .../templates/ObservableAccount.java | 2 + ParallelCounting/feedback_settings.yaml | 5 + ParallelCounting/public/ParallelCounting.java | 29 ++++ ParallelCounting/run | 22 +++ ParallelCounting/src/InginiousTests.java | 108 +++++++++++++ ParallelCounting/src/StudentTestRunner.java | 48 ++++++ .../src/ThreadPermissionFactory.java | 19 +++ ParallelCounting/task.yaml | 65 ++++++++ .../templates/ParallelCounting.java | 2 + .../unit_test/ParallelCountingTest.java | 54 +++++++ course.yaml | 148 ++++++++++-------- 17 files changed, 771 insertions(+), 65 deletions(-) create mode 100644 ObservableAccount/feedback_settings.yaml create mode 100644 ObservableAccount/public/ObservableAccount.java create mode 100644 ObservableAccount/run create mode 100644 ObservableAccount/src/InginiousTests.java create mode 100644 ObservableAccount/src/StudentTestRunner.java create mode 100644 ObservableAccount/task.yaml create mode 100644 ObservableAccount/templates/ObservableAccount.java create mode 100644 ParallelCounting/feedback_settings.yaml create mode 100644 ParallelCounting/public/ParallelCounting.java create mode 100644 ParallelCounting/run create mode 100644 ParallelCounting/src/InginiousTests.java create mode 100644 ParallelCounting/src/StudentTestRunner.java create mode 100644 ParallelCounting/src/ThreadPermissionFactory.java create mode 100644 ParallelCounting/task.yaml create mode 100644 ParallelCounting/templates/ParallelCounting.java create mode 100644 ParallelCounting/unit_test/ParallelCountingTest.java diff --git a/ObservableAccount/feedback_settings.yaml b/ObservableAccount/feedback_settings.yaml new file mode 100644 index 0000000..947f960 --- /dev/null +++ b/ObservableAccount/feedback_settings.yaml @@ -0,0 +1,5 @@ +# Example of file +exercise_type: default +has_feedback: True +quorum: 1.0 +feedback_kind: JavaGrading diff --git a/ObservableAccount/public/ObservableAccount.java b/ObservableAccount/public/ObservableAccount.java new file mode 100644 index 0000000..6085b5c --- /dev/null +++ b/ObservableAccount/public/ObservableAccount.java @@ -0,0 +1,68 @@ +/** + * This class implements a bank account. + * You can deposit and withdraw money from the account. + * Read carefully the comments of each method and fill the missing + * parts marked with "TODO". + * You can ADD any code you like in this class (new members, new methods, etc.). + * but do not add a package + */ + +public class ObservableAccount { + + public interface AccountObserver { + void accountHasChanged(); + } + + /** + * Get the account balance (franc. "solde") + * The initial balance of the account is 0. + * + * @return The balance + */ + public int getBalance() { + // TODO + return -100000; + } + + /** + * Deposit an amount into the account + * + * @param amount The amount to deposit + */ + public void deposit(int amount) { + // TODO + } + + /** + * Withdraw an amount from the account. + * An account cannot become negative. + * If you try to withdraw 1000 Euro from an account that has + * only 500 Euro, the withdrawal is NOT executed. + * + * @param amount The sum to withdraw + */ + public void withdraw(int amount) { + // TODO + } + + /** + * Add an observer to the account. + * The observer will be notified if an amount is deposited or withdrawn + * that is greater than the specified maximum. + * The observer must NOT be notified if the withdrawal is not executed + * (see comment of the method 'withdraw') + * + * The user of this class can change the maximum for an added observer by calling + * this method again with the same observer. Example: + * account.addObserver(myObserver,1000); + * account.addObserver(myObserver,2000); // change maximum for this observer + * + * @param observer The observer to add. + * @param maximum The observer will be notified if the deposited or withdrawn + * amount is greater than "maximum". + * + */ + public void addObserver(AccountObserver observer, int maximum) { + // TODO + } +} diff --git a/ObservableAccount/run b/ObservableAccount/run new file mode 100644 index 0000000..1abbd37 --- /dev/null +++ b/ObservableAccount/run @@ -0,0 +1,22 @@ +#!/bin/python3 +import importlib.util +import sys + + +# Dynamically load modules we need +# Credits to https://stackoverflow.com/a/67692/6149867 +# And for the explanation : http://www.blog.pythonlibrary.org/2016/05/27/python-201-an-intro-to-importlib/ +def dynamically_load_module(module, path): + spec = importlib.util.spec_from_file_location(module, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +##################################### +# Our import for common run file # +##################################### +sys.path.append("/course/common") + +runfile = dynamically_load_module("runfile", "/course/common/runfile.py") +runfile.main() diff --git a/ObservableAccount/src/InginiousTests.java b/ObservableAccount/src/InginiousTests.java new file mode 100644 index 0000000..0d88017 --- /dev/null +++ b/ObservableAccount/src/InginiousTests.java @@ -0,0 +1,86 @@ +package src; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.github.guillaumederval.javagrading.GradingRunner; +import com.github.guillaumederval.javagrading.Grade; +import com.github.guillaumederval.javagrading.GradeFeedback; + +import org.junit.Assert; + +import templates.*; + +@RunWith(GradingRunner.class) +public class InginiousTests { + int observerHasBeenNotified; + + @Test + @Grade(value = 1, cpuTimeout=1000) + @GradeFeedback(message="Balance should be correct after multiple deposits and withdrawals", onFail=true) + public void testBalance() { + ObservableAccount account=new ObservableAccount(); + + account.deposit(1500); + account.deposit(500); + account.withdraw(400); + Assert.assertEquals(1600,account.getBalance()); + } + + @Test + @Grade(value = 1, cpuTimeout=1000) + @GradeFeedback(message="Observer should be notified of large deposits and withdrawals", onFail=true) + public void testObserver() { + ObservableAccount account=new ObservableAccount(); + account.addObserver(() -> observerHasBeenNotified++, 1000); + + observerHasBeenNotified=0; + account.deposit(1500); + Assert.assertEquals(1, observerHasBeenNotified); + } + + @Test + @Grade(value = 1, cpuTimeout=1000) + @GradeFeedback(message="Withdrawals should not be executed if there is not enough money in the account", onFail=true) + public void testNotExecutedWithdrawal() { + ObservableAccount account=new ObservableAccount(); + account.addObserver(() -> observerHasBeenNotified++, 1000); + + observerHasBeenNotified=0; + account.deposit(500); + account.withdraw(1000); + Assert.assertEquals(0, observerHasBeenNotified); + } + + @Test + @Grade(value = 1, cpuTimeout=1000) + @GradeFeedback(message="Multiple observers with different maximums should be possible", onFail=true) + public void testMultipleObserver() { + ObservableAccount account=new ObservableAccount(); + account.addObserver(() -> observerHasBeenNotified++, 1000); + account.addObserver(() -> observerHasBeenNotified++, 500); + + observerHasBeenNotified=0; + account.deposit(800); + Assert.assertEquals(1, observerHasBeenNotified); + observerHasBeenNotified=0; + account.deposit(1500); + Assert.assertEquals(2, observerHasBeenNotified); + } + + @Test + @Grade(value = 1, cpuTimeout=1000) + @GradeFeedback(message="The maximum for a observer can be modified by calling addObserver() again", onFail=true) + public void testModifyObserver() { + ObservableAccount account=new ObservableAccount(); + ObservableAccount.AccountObserver observer= () -> observerHasBeenNotified++; + + observerHasBeenNotified=0; + account.addObserver(observer, 1000); + account.deposit(900); + account.addObserver(observer, 800); + account.deposit(900); + Assert.assertEquals(1, observerHasBeenNotified); + account.deposit(2000); + Assert.assertEquals(2, observerHasBeenNotified); + } +} diff --git a/ObservableAccount/src/StudentTestRunner.java b/ObservableAccount/src/StudentTestRunner.java new file mode 100644 index 0000000..66bc71e --- /dev/null +++ b/ObservableAccount/src/StudentTestRunner.java @@ -0,0 +1,48 @@ +package src; + +import com.github.guillaumederval.javagrading.GradingListener; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +import java.util.List; + +public class StudentTestRunner { + + public static void main(String [] args) { + + JUnitCore runner = new JUnitCore(); + runner.addListener(new GradingListener()); + Result result = runner.run(InginiousTests.class); + + if(result.wasSuccessful()){ + System.exit(0); + } else { + determineProblem(result); + } + } + + /* + * Makes the distinction between two different failure cases : + * - The student has a mistake in his/her code. (Sys exit 1) + * - The student used a forbidden instruction in his/her code. (Sys exit 2) + */ + private static void determineProblem(Result result){ + boolean flag = false; + + if(result.getFailureCount() != 0) { + List failures = result.getFailures(); + + for (Failure fail : failures) { + flag |= fail.getMessage()!= null && fail.getMessage().contains("access denied"); + } + } + + if(flag) { + System.exit(2); // The student used a forbidden instruction + } else { + System.exit(1); // There's an error in your code etc etc... + } + } + +} diff --git a/ObservableAccount/task.yaml b/ObservableAccount/task.yaml new file mode 100644 index 0000000..4e9af2d --- /dev/null +++ b/ObservableAccount/task.yaml @@ -0,0 +1,105 @@ +accessible: true +author: '' +categories: [] +contact_url: '' +context: |- + La classe ObservableAccount implemente un compte bancaire. Vous pouvez déposer et retirer de l'argent. Vous pouvez également ajouter des observateurs au compte qui seront avertis en cas de transactions importants. + + Lisez attentivement les commentaires de chaque méthode et remplissez les parties manquantes marquées par "TODO". + + Vous pouvez ajouter tout code que vous souhaitez dans cette classe (nouveaux membres, nouvelles méthodes, etc.). Naturellement, vous ne devez pas modifier les signatures des méthodes existantes. + +environment_id: java8scala +environment_parameters: + limits: + memory: '100' + time: '30' + hard_time: '' + run_cmd: '' +environment_type: docker +evaluate: best +file: '' +groups: false +input_random: '0' +name: ObservableAccount +network_grading: false +problems: + ObservableAccountMain: + name: '' + type: code + language: java + default: | + /** + * This class implements a bank account. + * You can deposit and withdraw money from the account. + * Read carefully the comments of each method and fill the missing + * parts marked with "TODO". + * You can ADD any code you like in this class (new members, new methods, etc.). + * You can also add imports. + */ + + public class ObservableAccount { + + public interface AccountObserver { + void accountHasChanged(); + } + + /** + * Get the account balance (franc. "solde") + * The initial balance of the account is 0. + * + * @return The balance + */ + public int getBalance() { + // TODO + return -100000; + } + + /** + * Deposit an amount into the account + * + * @param amount The amount to deposit + */ + public void deposit(int amount) { + // TODO + } + + /** + * Withdraw an amount from the account. + * An account cannot become negative. + * If you try to withdraw 1000 Euro from an account that has + * only 500 Euro, the withdrawal is NOT executed. + * + * @param amount The sum to withdraw + */ + public void withdraw(int amount) { + // TODO + } + + /** + * Add an observer to the account. + * The observer will be notified if an amount is deposited or withdrawn + * that is greater than the specified maximum. + * The observer must NOT be notified if the withdrawal is not executed + * (see comment of the method 'withdraw') + * + * The user of this class can change the maximum for an added observer by calling + * this method again with the same observer. Example: + * account.addObserver(myObserver,1000); + * account.addObserver(myObserver,2000); // change maximum for this observer + * + * @param observer The observer to add. + * @param maximum The observer will be notified if the deposited or withdrawn + * amount is greater than "maximum". + * + */ + public void addObserver(AccountObserver observer, int maximum) { + // TODO + } + } + header: Paste here the content of the `ObservableAccount.java` file +stored_submissions: 0 +submission_limit: + amount: -1 + period: -1 +weight: 1.0 diff --git a/ObservableAccount/templates/ObservableAccount.java b/ObservableAccount/templates/ObservableAccount.java new file mode 100644 index 0000000..7f9729a --- /dev/null +++ b/ObservableAccount/templates/ObservableAccount.java @@ -0,0 +1,2 @@ +package templates; +@@ObservableAccountMain@@ diff --git a/ParallelCounting/feedback_settings.yaml b/ParallelCounting/feedback_settings.yaml new file mode 100644 index 0000000..947f960 --- /dev/null +++ b/ParallelCounting/feedback_settings.yaml @@ -0,0 +1,5 @@ +# Example of file +exercise_type: default +has_feedback: True +quorum: 1.0 +feedback_kind: JavaGrading diff --git a/ParallelCounting/public/ParallelCounting.java b/ParallelCounting/public/ParallelCounting.java new file mode 100644 index 0000000..1eedff1 --- /dev/null +++ b/ParallelCounting/public/ParallelCounting.java @@ -0,0 +1,29 @@ +import java.util.Optional; + +/** + * You can ADD any code you like in this class (new members, new methods, etc.). + * You can also add imports. + */ + +public class ParallelCounting { + /** + * Return the number of values equal to v using a parallel algorithm. + * + * @param values an array of numbers + * @param v the value that you want to count + * @param nThreads is a value between 1 and values.length + * @return the number of elements equal to v in values (or 0 if no values are provided) + * + * Example: For + * values = [4.5f,3.2f,5.0f,6.6f,7.2f,1.5f,3.7f,5.8f,6.0f,9.0f,1.3f,2.3f,4.5f,1.5f] + * and + * v = 4.5 + * the method returns 2 because the value 4.5 appears two times in the array. + * + * Try to give all threads more or less the same amount of work! + */ + public static int parallelCount (Optional values, float v, int nThreads) { + // TODO + return -1; + } +} \ No newline at end of file diff --git a/ParallelCounting/run b/ParallelCounting/run new file mode 100644 index 0000000..1abbd37 --- /dev/null +++ b/ParallelCounting/run @@ -0,0 +1,22 @@ +#!/bin/python3 +import importlib.util +import sys + + +# Dynamically load modules we need +# Credits to https://stackoverflow.com/a/67692/6149867 +# And for the explanation : http://www.blog.pythonlibrary.org/2016/05/27/python-201-an-intro-to-importlib/ +def dynamically_load_module(module, path): + spec = importlib.util.spec_from_file_location(module, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +##################################### +# Our import for common run file # +##################################### +sys.path.append("/course/common") + +runfile = dynamically_load_module("runfile", "/course/common/runfile.py") +runfile.main() diff --git a/ParallelCounting/src/InginiousTests.java b/ParallelCounting/src/InginiousTests.java new file mode 100644 index 0000000..b4ed3ff --- /dev/null +++ b/ParallelCounting/src/InginiousTests.java @@ -0,0 +1,108 @@ +package src; + +import com.github.guillaumederval.javagrading.GradingRunner; +import com.github.guillaumederval.javagrading.Grade; +import com.github.guillaumederval.javagrading.GradeFeedback; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Optional; +import java.util.Random; + +import templates.*; + +@RunWith(GradingRunner.class) +public class InginiousTests { + + Random r = new Random(); + + @Test + @Grade(value = 1, cpuTimeout=1000, customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="Should work with one thread", onFail=true) + public void testSingleThread() { + float[] values = new float[] {1.5f,3.2f,5.0f,6.6f,7.2f,1.5f,3.7f,5.8f,6.0f,9.0f,1.3f,2.3f,4.5f,1.5f}; + Assert.assertEquals(3, ParallelCounting.parallelCount(Optional.of(values), 1.5f, 1)); + } + + @Test + @Grade(value = 1, cpuTimeout=1000, customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="Should work with all numbers of threads from 1 to values.length", onFail=true) + public void testMultipleThreads() { + float[] values = new float[] {1.5f,3.2f,5.0f,6.6f,7.2f,1.5f,3.7f,5.8f,6.0f,9.0f,1.3f,2.3f,4.5f,1.5f}; + for(int i=1;i<=values.length;i++) { + Assert.assertEquals(3, ParallelCounting.parallelCount(Optional.of(values), 1.5f, i)); + } + } + + @Test + @Grade(value = 1, cpuTimeout=1000, customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="Should also work with empty array", onFail=true) + public void testEmptyValues() { + Assert.assertEquals(0,ParallelCounting.parallelCount(Optional.of(new float[]{}),1.5f,2)); + } + + @Test + @Grade(value = 1, cpuTimeout=1000, customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="Should return 0 if no values are provided", onFail=true) + public void testNoValues() { + Assert.assertEquals(0,ParallelCounting.parallelCount(Optional.empty(),1.5f,2)); + } + + @Test + @Grade(value = 1, cpuTimeout=2000, customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="Should work with larger input (1 million array elements)", onFail=true) + public void testWithLargeInput() { + // make a large array + float[] values=new float[999_999]; + for(int i=0;i opt=Optional.of(values); + + Assert.assertEquals(values.length/3, ParallelCounting.parallelCount(opt, 1.0f, 3)); + } + + private int count(float [] values, float target) { + int count = 0; + for (float v : values) { + if (v == target) + count ++; + } + return count; + } + + @Test + @Grade(value=1,cpuTimeout=2000,customPermissions=ThreadPermissionFactory.class) + @GradeFeedback(message="You should use nThreads to do the computation", onFail=true) + public void testNumberThreads() { + int size = 100_000; + float [] values = new float[size]; + for (int i = 0; i < size; i++) + values[i] = r.nextFloat(); + + int [] maxNumberRunningThread = new int[]{-1}; + + Thread t = new Thread(new Runnable(){ + public void run() { + while (true) { + int nbRunningThread = Thread.getAllStackTraces().keySet().size(); + if (maxNumberRunningThread[0] < nbRunningThread) + maxNumberRunningThread[0] = nbRunningThread; + } + } + }); + t.setDaemon(true); + t.start(); + + // Initial count thread. The JVM will launch multiple thread to do various + // things, need to remove them from the last thread count + int initialThreadCount = Thread.getAllStackTraces().keySet().size(); + int nThreads = 3; + int count = ParallelCounting.parallelCount(Optional.of(values), values[0], nThreads); + + Assert.assertEquals(nThreads, maxNumberRunningThread[0] - initialThreadCount); + } + +} diff --git a/ParallelCounting/src/StudentTestRunner.java b/ParallelCounting/src/StudentTestRunner.java new file mode 100644 index 0000000..66bc71e --- /dev/null +++ b/ParallelCounting/src/StudentTestRunner.java @@ -0,0 +1,48 @@ +package src; + +import com.github.guillaumederval.javagrading.GradingListener; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; + +import java.util.List; + +public class StudentTestRunner { + + public static void main(String [] args) { + + JUnitCore runner = new JUnitCore(); + runner.addListener(new GradingListener()); + Result result = runner.run(InginiousTests.class); + + if(result.wasSuccessful()){ + System.exit(0); + } else { + determineProblem(result); + } + } + + /* + * Makes the distinction between two different failure cases : + * - The student has a mistake in his/her code. (Sys exit 1) + * - The student used a forbidden instruction in his/her code. (Sys exit 2) + */ + private static void determineProblem(Result result){ + boolean flag = false; + + if(result.getFailureCount() != 0) { + List failures = result.getFailures(); + + for (Failure fail : failures) { + flag |= fail.getMessage()!= null && fail.getMessage().contains("access denied"); + } + } + + if(flag) { + System.exit(2); // The student used a forbidden instruction + } else { + System.exit(1); // There's an error in your code etc etc... + } + } + +} diff --git a/ParallelCounting/src/ThreadPermissionFactory.java b/ParallelCounting/src/ThreadPermissionFactory.java new file mode 100644 index 0000000..9449989 --- /dev/null +++ b/ParallelCounting/src/ThreadPermissionFactory.java @@ -0,0 +1,19 @@ +package src; + +import com.github.guillaumederval.javagrading.Grade; + +import java.security.PermissionCollection; +import java.security.Permissions; + +public class ThreadPermissionFactory implements Grade.PermissionCollectionFactory { + + @Override + public PermissionCollection get() { + PermissionCollection coll = new Permissions(); + coll.add(new RuntimePermission("modifyThreadGroup")); + coll.add(new RuntimePermission("modifyThread")); + coll.add(new RuntimePermission("getStackTrace")); + return coll; + } + +} diff --git a/ParallelCounting/task.yaml b/ParallelCounting/task.yaml new file mode 100644 index 0000000..974b9b1 --- /dev/null +++ b/ParallelCounting/task.yaml @@ -0,0 +1,65 @@ +accessible: true +author: '' +categories: [] +contact_url: '' +context: |- + La méthode "parallelCount" compte le nombre d'occurrences d'une valeur "v" dans un tableau "valeurs". Pour accélérer le comptage, la méthode doit utiliser des threads. Le nombre de threads à utiliser est donné dans le paramètre "nThreads". + + Lisez attentivement les commentaires de chaque méthode et remplissez les parties manquantes marquées par "TODO". + + Vous pouvez ajouter tout code que vous souhaitez dans cette classe (nouveaux membres, nouvelles méthodes, etc.). Naturellement, vous ne devez pas modifier les signatures des méthodes existantes. +environment_id: java8scala +environment_parameters: + limits: + memory: '100' + time: '30' + hard_time: '' + run_cmd: '' +environment_type: docker +evaluate: best +file: '' +groups: false +input_random: '0' +name: ParallelCounting +network_grading: false +problems: + ParallelCountingMain: + default: |- + import java.util.Optional; + + /** + * You can ADD any code you like in this class (new members, new methods, etc.). + * You can also add imports. + */ + + public class ParallelCounting { + /** + * Return the number of values equal to v using a parallel algorithm. + * + * @param values an array of numbers + * @param v the value that you want to count + * @param nThreads is a value between 1 and values.length + * @return the number of elements equal to v in values (or 0 if no values are provided) + * + * Example: For + * values = [4.5f,3.2f,5.0f,6.6f,7.2f,1.5f,3.7f,5.8f,6.0f,9.0f,1.3f,2.3f,4.5f,1.5f] + * and + * v = 4.5 + * the method returns 2 because the value 4.5 appears two times in the array. + * + * Try to give all threads more or less the same amount of work! + */ + public static int parallelCount (Optional values, float v, int nThreads) { + // TODO + return -1; + } + } + name: '' + header: Paste here the content of the `ParallelCounting.java` file + type: code + language: java +stored_submissions: 0 +submission_limit: + amount: -1 + period: -1 +weight: 1.0 diff --git a/ParallelCounting/templates/ParallelCounting.java b/ParallelCounting/templates/ParallelCounting.java new file mode 100644 index 0000000..0ec2937 --- /dev/null +++ b/ParallelCounting/templates/ParallelCounting.java @@ -0,0 +1,2 @@ +package templates; +@@ParallelCountingMain@@ diff --git a/ParallelCounting/unit_test/ParallelCountingTest.java b/ParallelCounting/unit_test/ParallelCountingTest.java new file mode 100644 index 0000000..f693b17 --- /dev/null +++ b/ParallelCounting/unit_test/ParallelCountingTest.java @@ -0,0 +1,54 @@ +import org.junit.Assert; +import org.junit.Test; + +import java.util.Optional; + +public class ParallelCountingTest { + @Test + public void test1() { + float[] values = new float[] {4.5f,3.2f,5.0f,6.6f,7.2f,1.5f,3.7f,5.8f,6.0f,9.0f,1.3f,2.3f,4.5f,1.5f}; + Assert.assertEquals(2,ParallelCounting.parallelCount(Optional.of(values),4.5f,2)); + } + + @Test + public void test2() { + Assert.assertEquals(0,ParallelCounting.parallelCount(Optional.empty(),4.5f,2)); + } + + /** + * The next test checks whether your implementation with multiple threads is actually + * faster than with one single thread. + * Warning 1: This test is slow. Don't run it every time. + * Warning 2: This test might not be very reliable on your computer, depending what + * your computer is doing in the background, etc. + */ + @Test + public void test3() { + // make a large array + float[] values=new float[99_999_999*2]; + for(int i=0;i opt=Optional.of(values); + + // just a test to see whether the result is okay + Assert.assertEquals(values.length/3, ParallelCounting.parallelCount(opt, 1.0f, 1)); + + // Speed test. + // Using two threads should be at least 30% faster than using one thread: + + long t=System.currentTimeMillis(); + for(int i=0;i<10;i++) { + ParallelCounting.parallelCount(opt, 1.0f, 1); + } + long t1=System.currentTimeMillis()-t; + for(int i=0;i<10;i++) { + ParallelCounting.parallelCount(opt, 1.0f, 2); + } + long t2=System.currentTimeMillis()-t-t1; + System.out.println(t1+" "+t2); + Assert.assertTrue( + "Using two threads should be at least 30% faster than using one thread (see comments of this test)", + t2