diff --git a/hw1/.gitignore b/.gitignore
similarity index 100%
rename from hw1/.gitignore
rename to .gitignore
diff --git a/hw2/Ex1/.idea/Ex1.iml b/hw2/Ex1/.idea/Ex1.iml
new file mode 100644
index 0000000..b319ae2
--- /dev/null
+++ b/hw2/Ex1/.idea/Ex1.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/.idea/misc.xml b/hw2/Ex1/.idea/misc.xml
new file mode 100644
index 0000000..0c31c09
--- /dev/null
+++ b/hw2/Ex1/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/.idea/modules.xml b/hw2/Ex1/.idea/modules.xml
new file mode 100644
index 0000000..2f08044
--- /dev/null
+++ b/hw2/Ex1/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/.idea/uiDesigner.xml b/hw2/Ex1/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/hw2/Ex1/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/.idea/vcs.xml b/hw2/Ex1/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/hw2/Ex1/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/.idea/workspace.xml b/hw2/Ex1/.idea/workspace.xml
new file mode 100644
index 0000000..8e0ee87
--- /dev/null
+++ b/hw2/Ex1/.idea/workspace.xml
@@ -0,0 +1,383 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ root
+ OCCUR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1573115638539
+
+
+ 1573115638539
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ex1:jar
+
+
+
+
+
+
+
+
+
+
+
+ No facets are configured
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 12
+
+
+
+
+
+
+
+
+
+
+
+ Ex1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw2/Ex1/src/bintree/BinTree.java b/hw2/Ex1/src/bintree/BinTree.java
new file mode 100644
index 0000000..c78bb56
--- /dev/null
+++ b/hw2/Ex1/src/bintree/BinTree.java
@@ -0,0 +1,18 @@
+package bintree;
+
+public interface BinTree {
+
+ /**
+ * Inserts value in this tree
+ * @param value
+ */
+ void insert(int value);
+
+ /**
+ * Returns the number of occurrences of value in this tree
+ * @param value
+ * @return the number of occurrences of value in the tree
+ */
+ int occurs(int value);
+
+}
diff --git a/hw2/Ex1/src/bintree/BinTreeCAS.java b/hw2/Ex1/src/bintree/BinTreeCAS.java
new file mode 100644
index 0000000..86cc75b
--- /dev/null
+++ b/hw2/Ex1/src/bintree/BinTreeCAS.java
@@ -0,0 +1,64 @@
+package bintree;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class BinTreeCAS implements BinTree {
+
+ private static class Node {
+ final int value;
+ AtomicInteger occ;
+ AtomicReference left, right;
+
+ private Node(int value, int initOcc) {
+ this.value = value;
+ occ = new AtomicInteger(initOcc);
+
+ left = new AtomicReference<>();
+ left.set(null);
+
+ right = new AtomicReference<>();
+ right.set(null);
+ }
+ }
+
+ private final Node root = new Node(0, 0);
+
+ public void insert(int value) {
+ Node n = root;
+ while (true) {
+ int nval = n.value;
+ if (value == nval) {
+ n.occ.addAndGet(1);
+ return;
+ }
+ else if (value < nval) {
+ if (n.left.compareAndSet(null, new Node(value, 1))) {
+ return;
+ } else {
+ n = n.left.get();
+ }
+ }
+ else { // value > nval
+ if (n.right.compareAndSet(null, new Node(value, 1))) {
+ return;
+ } else {
+ n = n.right.get();
+ }
+ }
+ }
+ }
+
+ public int occurs(int value) {
+ Node n = root;
+ do {
+ int nval = n.value;
+ if (value == nval) {
+ return n.occ.intValue();
+ }
+ n = (value < nval) ? n.left.get() : n.right.get();
+ } while (n != null);
+ // value not found
+ return 0;
+ }
+}
diff --git a/hw2/Ex1/src/bintree/BinTreeFullSync.java b/hw2/Ex1/src/bintree/BinTreeFullSync.java
new file mode 100644
index 0000000..f13940c
--- /dev/null
+++ b/hw2/Ex1/src/bintree/BinTreeFullSync.java
@@ -0,0 +1,55 @@
+package bintree;
+
+public class BinTreeFullSync implements BinTree {
+
+ private static class Node {
+ final int value;
+ int occ;
+ Node left, right;
+
+ private Node(int value, int initOcc) {
+ this.value = value;
+ occ = initOcc;
+ }
+ }
+
+ private final Node root = new Node(0, 0);
+
+ public synchronized void insert(int value) {
+ Node n = root;
+ while (true) {
+ int nval = n.value;
+ if (value == nval) {
+ n.occ++;
+ return;
+ }
+ else if (value < nval) {
+ if (n.left == null) {
+ n.left = new Node(value, 1);
+ return;
+ }
+ n = n.left;
+ }
+ else { // value > nval
+ if (n.right == null) {
+ n.right = new Node(value, 1);
+ return;
+ }
+ n = n.right;
+ }
+ }
+ }
+
+ public synchronized int occurs(int value) {
+ Node n = root;
+ do {
+ int nval = n.value;
+ if (value == nval) {
+ return n.occ++;
+ }
+ n = (value < nval) ? n.left : n.right;
+ } while (n != null);
+ // value not found
+ return 0;
+ }
+}
diff --git a/hw2/Ex1/src/bintree/BinTreeFullSyncEdited.java b/hw2/Ex1/src/bintree/BinTreeFullSyncEdited.java
new file mode 100644
index 0000000..7ae40a0
--- /dev/null
+++ b/hw2/Ex1/src/bintree/BinTreeFullSyncEdited.java
@@ -0,0 +1,71 @@
+package bintree;
+
+public class BinTreeFullSyncEdited implements BinTree {
+
+ private static class Node {
+ final int value;
+ int occ;
+ Node left, right;
+
+ private Node(int value, int initOcc) {
+ this.value = value;
+ occ = initOcc;
+ }
+
+ private synchronized int getOcc() {
+ return occ;
+ }
+
+ private synchronized void incrementOcc() {
+ occ++;
+ }
+
+ private synchronized Node goLeftOrNull(int value) {
+ if (this.left == null) {
+ this.left = new Node(value, 1);
+ return null;
+ }
+ return this.left;
+ }
+
+ private synchronized Node goRightOrNull(int value) {
+ if (this.right == null) {
+ this.right = new Node(value, 1);
+ return null;
+ }
+ return this.right;
+ }
+ }
+
+ private final Node root = new Node(0, 0);
+
+ public void insert(int value) {
+ Node n = root;
+ while (n != null) {
+ int nval = n.value;
+ if (value == nval) {
+ n.incrementOcc();
+ return;
+ }
+ else if (value < nval) {
+ n = n.goLeftOrNull(value);
+ }
+ else { // value > nval
+ n = n.goRightOrNull(value);
+ }
+ }
+ }
+
+ public int occurs(int value) {
+ Node n = root;
+ do {
+ int nval = n.value;
+ if (value == nval) {
+ return n.getOcc();
+ }
+ n = (value < nval) ? n.left : n.right;
+ } while (n != null);
+ // value not found
+ return 0;
+ }
+}
diff --git a/hw2/Ex1/src/bintree/BinTreeSimple.java b/hw2/Ex1/src/bintree/BinTreeSimple.java
new file mode 100644
index 0000000..0ee7523
--- /dev/null
+++ b/hw2/Ex1/src/bintree/BinTreeSimple.java
@@ -0,0 +1,57 @@
+package bintree;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BinTreeSimple implements BinTree {
+
+ private static class Node {
+ final int value;
+ int occ;
+ Node left, right;
+
+ private Node(int value, int initOcc) {
+ this.value = value;
+ occ = initOcc;
+ }
+ }
+
+ private final Node root = new Node(0, 0);
+
+ public void insert(int value) {
+ Node n = root;
+ while (true) {
+ int nval = n.value;
+ if (value == nval) {
+ n.occ++;
+ return;
+ }
+ else if (value < nval) {
+ if (n.left == null) {
+ n.left = new Node(value, 1);
+ return;
+ }
+ n = n.left;
+ }
+ else { // value > nval
+ if (n.right == null) {
+ n.right = new Node(value, 1);
+ return;
+ }
+ n = n.right;
+ }
+ }
+ }
+
+ public int occurs(int value) {
+ Node n = root;
+ do {
+ int nval = n.value;
+ if (value == nval) {
+ return n.occ++;
+ }
+ n = (value < nval) ? n.left : n.right;
+ } while (n != null);
+ // value not found
+ return 0;
+ }
+}
diff --git a/hw2/Ex1/src/bintree/Tester.java b/hw2/Ex1/src/bintree/Tester.java
new file mode 100644
index 0000000..602d008
--- /dev/null
+++ b/hw2/Ex1/src/bintree/Tester.java
@@ -0,0 +1,97 @@
+package bintree;
+
+import java.util.concurrent.CountDownLatch;
+
+public class Tester {
+
+ private static final int NUM_THREADS = 1024;
+ private static final int NUM_ITERATIONS = 64;
+ private static final int OCCUR = 32;
+ private final BinTree tree;
+ private final CountDownLatch threadsReady,
+ measurementStarted, threadsCompleted;
+
+ private class TesterThread extends Thread {
+
+ private final int startValue;
+
+ TesterThread(int startValue) {
+ this.startValue = startValue;
+ }
+
+ public void run() {
+ int iter = NUM_ITERATIONS * OCCUR;
+ int nextValue = startValue;
+
+ threadsReady.countDown();
+
+ try {
+ measurementStarted.await();
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ for (int i = 0; i < iter; i++) {
+ tree.insert(nextValue);
+ nextValue = (nextValue + 1) % NUM_ITERATIONS;
+ }
+
+ threadsCompleted.countDown();
+ }
+ }
+
+ public Tester(BinTree tree) {
+ this.tree = tree;
+ this.threadsReady = new CountDownLatch(NUM_THREADS);
+ this.measurementStarted = new CountDownLatch(1);
+ this.threadsCompleted = new CountDownLatch(NUM_THREADS);
+ }
+
+ private long runMeasurement() throws InterruptedException {
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ Thread t = new TesterThread( NUM_ITERATIONS / 2);
+ t.start();
+ }
+
+ threadsReady.await();
+ long timeBegin = System.nanoTime();
+
+ measurementStarted.countDown();
+
+ threadsCompleted.await();
+ long timeEnd = System.nanoTime();
+
+ return timeEnd - timeBegin;
+ }
+
+ private void checkTree() {
+ int expectedOccur = OCCUR * NUM_THREADS;
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ int foundOccur;
+ if ((foundOccur = tree.occurs(i)) != expectedOccur) {
+ System.err.printf(" - ERROR: Expected: %d ; Found: %d\n",
+ expectedOccur, foundOccur);
+ }
+ }
+ }
+
+ private static void testTreeImplementation(BinTree implementation,
+ String name) throws Exception {
+
+ System.out.println("Results for implementation: " + name);
+ Tester tester = new Tester(implementation);
+ long elapsedTime = tester.runMeasurement();
+ tester.checkTree();
+ System.out.printf(" - Test completed, elapsed time: %d ms\n",
+ (elapsedTime / 1000000));
+ }
+
+ public static void main(String[] args) throws Exception {
+ //testTreeImplementation(new BinTreeSimple(), "Simple version");
+ testTreeImplementation(new BinTreeFullSyncEdited(), "Synchronized version");
+ testTreeImplementation(new BinTreeFullSyncEdited(), "Synchronized version (Edited)");
+ testTreeImplementation(new BinTreeCAS(), "CAS version");
+ }
+}
diff --git a/hw2/Ex3/src/parallel/CallablePrimeCounter.java b/hw2/Ex3/src/parallel/CallablePrimeCounter.java
new file mode 100644
index 0000000..6aeb443
--- /dev/null
+++ b/hw2/Ex3/src/parallel/CallablePrimeCounter.java
@@ -0,0 +1,55 @@
+package parallel;
+
+import util.Prime;
+import java.util.List;
+import util.PrimeCounter;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+public class CallablePrimeCounter implements PrimeCounter {
+
+ private final int numThreads;
+
+ public CallablePrimeCounter(int numThreads) {
+ this.numThreads = numThreads;
+ }
+
+ public int countPrimes(int[] nums) throws Exception {
+ int count = 0;
+ List> futureTasks = new ArrayList<>(numThreads);
+ int size = (int) Math.ceil((double) nums.length / numThreads);
+ for (int i = 0; i < numThreads; i++) {
+ FutureTask future =
+ new FutureTask<>(new CountPrimes(nums, i * size, (i + 1) * size));
+ futureTasks.add(future);
+ new Thread(future).start();
+ }
+ for (FutureTask task : futureTasks) {
+ count += task.get();
+ }
+ return count;
+ }
+
+ private static class CountPrimes implements Callable {
+ private final int[] nums;
+ private final int low, high;
+
+ private CountPrimes(int[] nums, int low, int high) {
+ this.nums = nums;
+ this.low = low;
+ this.high = Math.min(high, nums.length);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ int count = 0;
+ for (int i = low; i < high; i++) {
+ if (Prime.isPrime(nums[i])) {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+}
diff --git a/hw2/Ex3/src/parallel/ForkJoinPoolPrimeCounter.java b/hw2/Ex3/src/parallel/ForkJoinPoolPrimeCounter.java
new file mode 100644
index 0000000..81b50ae
--- /dev/null
+++ b/hw2/Ex3/src/parallel/ForkJoinPoolPrimeCounter.java
@@ -0,0 +1,62 @@
+package parallel;
+
+import util.Prime;
+import util.PrimeCounter;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RecursiveTask;
+
+public class ForkJoinPoolPrimeCounter implements PrimeCounter {
+
+ private static final int SEQUENTIAL_THRESHOLD = 1000;
+ private final int numThreads;
+
+ public ForkJoinPoolPrimeCounter(int numThreads) {
+ this.numThreads = numThreads;
+ }
+
+ public int countPrimes(int[] nums) {
+ int count = 0;
+ // TODO: Complete method countPrimes
+
+ return count;
+ }
+
+ private static class CountPrimes extends RecursiveTask {
+
+ private final int low, high;
+ private final int[] nums;
+
+ public CountPrimes(int[] nums, int low, int high) {
+ this.nums = nums;
+ this.low = low;
+ this.high = high;
+ }
+
+ @Override
+ protected Integer compute() {
+ if (low > high) {
+ return 0;
+ }
+ if ((high - low) <= SEQUENTIAL_THRESHOLD) {
+ int count = 0;
+ for (int i = low; i <= high; i++) {
+ if (Prime.isPrime(nums[i])) {
+ count++;
+ }
+ }
+ return count;
+ }
+ else {
+ int right, left, rightAns, leftAns;
+ right = left = rightAns = leftAns = 0;
+ right = low + ((int) Math.floor((high - low) / 2 ) - 1);
+ left = low + ((int) Math.ceil((high - low) / 2 ));
+ // TODO: Complete method compute
+
+
+
+ return leftAns + rightAns;
+ }
+ }
+ }
+}
diff --git a/hw2/Ex3/src/parallel/ThreadPoolPrimeCounter.java b/hw2/Ex3/src/parallel/ThreadPoolPrimeCounter.java
new file mode 100644
index 0000000..5824119
--- /dev/null
+++ b/hw2/Ex3/src/parallel/ThreadPoolPrimeCounter.java
@@ -0,0 +1,49 @@
+package parallel;
+
+import util.Prime;
+import java.util.List;
+import util.PrimeCounter;
+import java.util.ArrayList;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+
+public class ThreadPoolPrimeCounter implements PrimeCounter {
+
+ private final int numThreads;
+
+ public ThreadPoolPrimeCounter(int numThreads) {
+ this.numThreads = numThreads;
+ }
+
+ public int countPrimes(int[] nums) throws Exception {
+ int count = 0;
+ // TODO: Complete method countPrimes
+
+ return count;
+ }
+
+ private static class CountPrimes implements Callable {
+ private final int[] nums;
+ private final int low, high;
+
+ private CountPrimes(int[] nums, int low, int high) {
+ this.nums = nums;
+ this.low = low;
+ this.high = Math.min(high, nums.length);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ int count = 0;
+ for (int i = low; i < high; i++) {
+ if (Prime.isPrime(nums[i])) {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+}
diff --git a/hw2/Ex3/src/sequential/SequentialPrimeCounter.java b/hw2/Ex3/src/sequential/SequentialPrimeCounter.java
new file mode 100644
index 0000000..337673b
--- /dev/null
+++ b/hw2/Ex3/src/sequential/SequentialPrimeCounter.java
@@ -0,0 +1,17 @@
+package sequential;
+
+import util.Prime;
+import util.PrimeCounter;
+
+public class SequentialPrimeCounter implements PrimeCounter {
+
+ public int countPrimes(int[] nums) {
+ int count = 0;
+ for (int i = 0; i < nums.length; i++) {
+ if (Prime.isPrime(nums[i])) {
+ count++;
+ }
+ }
+ return count;
+ }
+}
diff --git a/hw2/Ex3/src/test/Tester.java b/hw2/Ex3/src/test/Tester.java
new file mode 100644
index 0000000..970e95c
--- /dev/null
+++ b/hw2/Ex3/src/test/Tester.java
@@ -0,0 +1,73 @@
+package test;
+
+import util.PrimeCounter;
+import java.util.stream.IntStream;
+import parallel.CallablePrimeCounter;
+import parallel.ThreadPoolPrimeCounter;
+import sequential.SequentialPrimeCounter;
+import parallel.ForkJoinPoolPrimeCounter;
+
+public class Tester {
+
+ private static final int NUM_THREADS = 8;
+ public static final int LOW = 2;
+ public static final int HIGH = 11201609;
+ private PrimeCounter strategy;
+
+ private void setStrategy(PrimeCounter strategy) {
+ this.strategy = strategy;
+ }
+
+ private int countPrimes(int[] array) {
+ return new SequentialPrimeCounter().countPrimes(array);
+ }
+
+ private void testImplementation(int[] array, String name)
+ throws Exception {
+
+ long startTime = System.nanoTime();
+ int count = strategy.countPrimes(array);
+ long endTime = System.nanoTime();
+ long result = countPrimes(array);
+ if (count != result) {
+ // Informing if the implementation failed
+ System.err.printf("- ERROR: %s; Expected: %d; Found: %d\n",
+ name, result, count);
+ } else {
+ // Showing the time taken by the implementation
+ System.out.printf("- %s: %d prime numbers found, "
+ + "elapsed time: %d ms\n" , name, count,
+ ((endTime - startTime) / 1000000));
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ //Generating an integer array with numbers in the range from LOW to HIGH
+ int[] numbers = IntStream.rangeClosed(LOW, HIGH).toArray();
+ Tester tester = new Tester();
+
+ // Testing different implementations:
+ // Sequential implementation
+ tester.setStrategy(new SequentialPrimeCounter());
+ tester.testImplementation(numbers,"Sequential version");
+
+ // Parallel - Callable implementation
+ tester.setStrategy(new CallablePrimeCounter(NUM_THREADS));
+ tester.testImplementation(numbers, "Parallel - Callable version");
+
+ // TODO: Uncomment to test additional implementations
+ /*
+ // Parallel - ThreadPool implementation
+ tester.setStrategy(new ThreadPoolPrimeCounter(NUM_THREADS));
+ tester.testImplementation(numbers, "Parallel - ThreadPool version");
+
+ // Parallel - ForkJoinPool implementation - Ex. 4
+ tester.setStrategy(new ForkJoinPoolPrimeCounter(NUM_THREADS));
+ tester.testImplementation(numbers, "Parallel - ForkJoinPool version");
+
+ // Parallel - Streams implementation - BONUS
+ //tester.setStrategy(new StreamsPrimeCounter());
+ //tester.testImplementation(numbers, "Parallel - Streams version");
+ */
+ }
+}
diff --git a/hw2/Ex3/src/util/Prime.java b/hw2/Ex3/src/util/Prime.java
new file mode 100644
index 0000000..364445f
--- /dev/null
+++ b/hw2/Ex3/src/util/Prime.java
@@ -0,0 +1,19 @@
+package util;
+
+public class Prime {
+
+ public static boolean isPrime(int n) {
+ if (n <= 2) {
+ return n == 2;
+ }
+ if ((n&1) == 0) {
+ return false;
+ }
+ for (int i = 3; i*i <= n; i += 2) {
+ if (n % i == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/hw2/Ex3/src/util/PrimeCounter.java b/hw2/Ex3/src/util/PrimeCounter.java
new file mode 100644
index 0000000..f613c88
--- /dev/null
+++ b/hw2/Ex3/src/util/PrimeCounter.java
@@ -0,0 +1,6 @@
+package util;
+
+@FunctionalInterface
+public interface PrimeCounter {
+ int countPrimes(int[] nums) throws Exception;
+}
diff --git a/hw2/submission.tex b/hw2/submission.tex
new file mode 100644
index 0000000..5511096
--- /dev/null
+++ b/hw2/submission.tex
@@ -0,0 +1,23 @@
+\documentclass[12pt,a4paper]{article}
+
+\usepackage[utf8]{inputenc}
+\usepackage[margin=2cm]{geometry}
+
+\title{Howework 2 -- Programming Fundamentals 3}
+\author{Claudio Maggioni}
+
+\begin{document}
+\maketitle
+\tableofcontents
+\section{Exercise 1}
+\subsection{Question 2}
+Results returned by \texttt{BinTreeSimple} are wrong since the class is not thread safe. In particular, \texttt{BinTreeSimple.insert(int)} has race conditions on the integer field occ of each node, and the fields left and right on each node. To fix this, an AtomicInteger could be used for occ and access on n.left and n.right could be synchronized.
+
+\subsection{Question 3: Note on implementation}
+I have implemented the class \texttt{BinTreeFullSync}
+as a thread-safe alternative of \texttt{BinTreeSimple} where the only code modification between the two were the addition of \texttt{synchronized} keywords on already existing threads. Since I was not sure how to interpret this specific question, I have implemented \texttt{BinTreeFullSyncEdited}, a thread-safe refactoring of \texttt{BinTreeSimple} where the only synchronization mechanism is method-level \texttt{synchronized} blocks, which are used on new methods created in the subclass \texttt{Node}.
+
+\subsection{Question 5}
+\texttt{BinTreeFullSync} has the worst performance of all 3 implementations since it allows only sequential access to the tree structure. \texttt{BinTreeFullSyncEdited} is slightly faster, but \texttt{BinTreeCAS} is the fastest since the first one is a \texttt{synchronized} block imitation of the second one, which is instead based on \texttt{Atomic*} objects and can use the extra speed provided by architecture-based optimization.
+
+\end{document}