From b401414d33e8e138b532e8e9626b0c060c48fb58 Mon Sep 17 00:00:00 2001
From: anniemao <amao9098@gmail.com>
Date: Wed, 29 Apr 2020 23:25:13 -0700
Subject: [PATCH] Add MinFourHeap and remove NGrams from p2

---
 src/datastructures/worklists/MinFourHeap.java |  47 +++++
 .../wordsuggestor/NGramToNextChoicesMap.java  |  32 +++-
 src/tests/gitlab/ckpt1/Ckpt1Tests.java        |   3 +-
 src/tests/gitlab/ckpt1/MinFourHeapTests.java  | 171 +++++++++++++++++
 .../ckpt1/NGramToNextChoicesMapTests.java     | 172 ------------------
 .../gitlab/ckpt1/WorklistGradingTests.java    |  99 ++++++++++
 6 files changed, 349 insertions(+), 175 deletions(-)
 create mode 100644 src/datastructures/worklists/MinFourHeap.java
 create mode 100644 src/tests/gitlab/ckpt1/MinFourHeapTests.java
 delete mode 100644 src/tests/gitlab/ckpt1/NGramToNextChoicesMapTests.java
 create mode 100644 src/tests/gitlab/ckpt1/WorklistGradingTests.java

diff --git a/src/datastructures/worklists/MinFourHeap.java b/src/datastructures/worklists/MinFourHeap.java
new file mode 100644
index 0000000..bb02bd6
--- /dev/null
+++ b/src/datastructures/worklists/MinFourHeap.java
@@ -0,0 +1,47 @@
+package datastructures.worklists;
+
+import cse332.exceptions.NotYetImplementedException;
+import cse332.interfaces.worklists.PriorityWorkList;
+
+/**
+ * See cse332/interfaces/worklists/PriorityWorkList.java
+ * for method specifications.
+ */
+public class MinFourHeap<E extends Comparable<E>> extends PriorityWorkList<E> {
+    /* Do not change the name of this field; the tests rely on it to work correctly. */
+    private E[] data;
+    
+    public MinFourHeap() {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public boolean hasWork() {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public void add(E work) {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public E peek() {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public E next() {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public int size() {
+        throw new NotYetImplementedException();
+    }
+
+    @Override
+    public void clear() {
+        throw new NotYetImplementedException();
+    }
+}
diff --git a/src/p2/wordsuggestor/NGramToNextChoicesMap.java b/src/p2/wordsuggestor/NGramToNextChoicesMap.java
index 2f72f87..7420196 100644
--- a/src/p2/wordsuggestor/NGramToNextChoicesMap.java
+++ b/src/p2/wordsuggestor/NGramToNextChoicesMap.java
@@ -1,6 +1,7 @@
 package p2.wordsuggestor;
 
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.function.Supplier;
 
 import cse332.datastructures.containers.Item;
@@ -26,7 +27,18 @@ public class NGramToNextChoicesMap {
      * Increments the count of word after the particular NGram ngram.
      */
     public void seenWordAfterNGram(NGram ngram, String word) {
-        throw new NotYetImplementedException();
+        Dictionary<AlphabeticString, Integer> counter = map.find((NGram) ngram);
+        if (counter == null) {
+            counter = newInner.get();
+            map.insert((NGram) ngram, counter);
+        }
+
+        Integer prev = counter.find(new AlphabeticString(word));
+        if (prev == null) {
+            prev = 0;
+        }
+        counter.insert(new AlphabeticString(word), prev + 1);
+
     }
 
     /**
@@ -39,7 +51,23 @@ public class NGramToNextChoicesMap {
      * @return An array of all the Items for the requested ngram.
      */
     public Item<String, Integer>[] getCountsAfter(NGram ngram) {
-        throw new NotYetImplementedException();
+        if (ngram == null) {
+            return (Item<String, Integer>[]) new Item[0];
+        }
+        Dictionary<AlphabeticString, Integer> counter = map.find((NGram) ngram);
+        Item<String, Integer>[] result = (Item<String, Integer>[]) new Item[counter != null
+                ? counter.size() : 0];
+        if (counter != null) {
+            Iterator<Item<AlphabeticString, Integer>> it = counter.iterator();
+
+            for (int i = 0; i < result.length; i++) {
+                Item<AlphabeticString, Integer> item = it.next();
+                result[i] = new Item<String, Integer>(item.key.toString(),
+                        item.value);
+            }
+        }
+        return result;
+
     }
 
     public String[] getWordsAfter(NGram ngram, int k) {
diff --git a/src/tests/gitlab/ckpt1/Ckpt1Tests.java b/src/tests/gitlab/ckpt1/Ckpt1Tests.java
index 68c6d31..0bc8b47 100644
--- a/src/tests/gitlab/ckpt1/Ckpt1Tests.java
+++ b/src/tests/gitlab/ckpt1/Ckpt1Tests.java
@@ -1,12 +1,13 @@
 package tests.gitlab.ckpt1;
 
+import datastructures.worklists.MinFourHeap;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 
 @Suite.SuiteClasses({
-        NGramToNextChoicesMapTests.class,
+        MinFourHeap.class,
         MoveToFrontListTests.class,
         CircularArrayComparatorTests.class
 })
diff --git a/src/tests/gitlab/ckpt1/MinFourHeapTests.java b/src/tests/gitlab/ckpt1/MinFourHeapTests.java
new file mode 100644
index 0000000..76d9363
--- /dev/null
+++ b/src/tests/gitlab/ckpt1/MinFourHeapTests.java
@@ -0,0 +1,171 @@
+package tests.gitlab.ckpt1;
+
+import cse332.interfaces.worklists.PriorityWorkList;
+import datastructures.worklists.MinFourHeap;
+import org.junit.Before;
+import org.junit.Test;
+import tests.gitlab.ckpt1.WorklistGradingTests;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.Random;
+
+import static org.junit.Assert.*;
+
+public class MinFourHeapTests extends WorklistGradingTests {
+    private static Random RAND;
+
+    @Before
+    public void init() {
+        STUDENT_STR = new MinFourHeap<>();
+        STUDENT_DOUBLE = new MinFourHeap<>();
+        STUDENT_INT = new MinFourHeap<>();
+        RAND = new Random(42);
+    }
+
+    @Test(timeout = 3000)
+    public void testHeapWith5Items() {
+        PriorityWorkList<String> heap = new MinFourHeap<>();
+        String[] tests = { "a", "b", "c", "d", "e" };
+        for (int i = 0; i < 5; i++) {
+            String str = tests[i] + "a";
+            heap.add(str);
+        }
+
+        for (int i = 0; i < 5; i++) {
+            String str_heap = heap.next();
+            String str = (char) ('a' + i) + "a";
+            assertEquals(str, str_heap);
+        }
+    }
+
+    @Test(timeout = 3000)
+    public void testOrderingDoesNotMatter() {
+        PriorityWorkList<String> ordered = new MinFourHeap<>();
+        PriorityWorkList<String> reversed = new MinFourHeap<>();
+        PriorityWorkList<String> random = new MinFourHeap<>();
+
+        addAll(ordered, new String[]{"a", "b", "c", "d", "e"});
+        addAll(reversed, new String[]{"e", "d", "c", "b", "a"});
+        addAll(random, new String[]{"d", "b", "c", "e", "a"});
+
+        assertTrue(isSame("a", ordered.peek(), reversed.peek(), random.peek()));
+        assertTrue(isSame("a", ordered.next(), reversed.next(), random.next()));
+        assertTrue(isSame("b", ordered.next(), reversed.next(), random.next()));
+
+        addAll(ordered, new String[] {"a", "a", "b", "c", "z"});
+        addAll(reversed, new String[] {"z", "c", "b", "a", "a"});
+        addAll(random, new String[] {"c", "z", "a", "b", "a"});
+
+        String[] expected = new String[] {"a", "a", "b", "c", "c", "d", "e", "z"};
+        for (String e : expected) {
+            assertTrue(isSame(e, ordered.peek(), reversed.peek(), random.peek()));
+            assertTrue(isSame(e, ordered.next(), reversed.next(), random.next()));
+        }
+    }
+
+    private boolean isSame(String... args) {
+        String first = args[0];
+        for (String arg : args) {
+            if (!first.equals(arg)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Test(timeout = 3000)
+    public void testHugeHeap() {
+        PriorityWorkList<String> heap = new MinFourHeap<>();
+        int n = 10000;
+
+        // Add them
+        for (int i = 0; i < n; i++) {
+            String str = String.format("%05d", i * 37 % n);
+            heap.add(str);
+        }
+        // Delete them all
+        for (int i = 0; i < n; i++) {
+            String s = heap.next();
+            assertEquals(i , Integer.parseInt(s));
+        }
+    }
+
+    @Test(timeout = 3000)
+    public void testWithCustomComparable() {
+        PriorityWorkList<Coordinate> student = new MinFourHeap<>();
+        Queue<Coordinate> reference = new PriorityQueue<>();
+
+        for (int i = 0; i < 10000; i++) {
+            Coordinate coord = new Coordinate(RAND.nextInt(10000) - 5000, RAND.nextInt(10000) - 5000);
+            student.add(coord);
+            reference.add(coord);
+        }
+        assertEquals(reference.size(), student.size());
+
+        while (!reference.isEmpty()) {
+            assertEquals(reference.peek() , student.peek());
+            assertEquals(reference.remove() , student.next());
+        }
+    }
+
+    public static class Coordinate implements Comparable<Coordinate> {
+        private int x;
+        private int y;
+
+        public Coordinate(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        // What exactly this comparable method is doing is somewhat arbitrary.
+        public int compareTo(Coordinate other) {
+            if (this.x != other.x) {
+                return this.x - other.x;
+            } else {
+                return this.y - other.y;
+            }
+        }
+    }
+
+    @Test(timeout = 3000)
+    public void checkStructure() {
+        PriorityWorkList<Integer> heap = new MinFourHeap<>();
+        addAll(heap, new Integer[] {10, 10, 15, 1, 17, 16, 100, 101, 102, 103, 105, 106, 107, 108});
+
+        Object[] heapData = getField(heap, "data");
+        String heapStr = Arrays.toString(heapData);
+        String heapExp = "[1, 10, 15, 10, 17, 16, 100, 101, 102, 103, 105, 106, 107, 108";
+
+        heap.next();
+        heap.next();
+        heap.next();
+
+        Object[] heapData2 = getField(heap, "data");
+        String heapStr2 = Arrays.toString(heapData2);
+        String heapExp2 = "[15, 16, 103, 107, 17, 108, 100, 101, 102, 106, 105,";
+
+        assertTrue(heapStr.contains(heapExp));
+        assertTrue(heapStr2.contains(heapExp2));
+    }
+
+    protected <T> T getField(Object o, String fieldName) {
+        try {
+            Field field = o.getClass().getSuperclass().getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Object f = field.get(o);
+            return (T) f;
+        } catch (Exception var6) {
+            try {
+                Field field = o.getClass().getDeclaredField(fieldName);
+                field.setAccessible(true);
+                Object f = field.get(o);
+                return (T) f;
+            } catch (Exception var5) {
+                return null;
+            }
+        }
+    }
+}
diff --git a/src/tests/gitlab/ckpt1/NGramToNextChoicesMapTests.java b/src/tests/gitlab/ckpt1/NGramToNextChoicesMapTests.java
deleted file mode 100644
index 85d65dc..0000000
--- a/src/tests/gitlab/ckpt1/NGramToNextChoicesMapTests.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package tests.gitlab.ckpt1;
-
-import cse332.datastructures.containers.Item;
-import cse332.datastructures.trees.BinarySearchTree;
-import cse332.types.NGram;
-import org.junit.Test;
-import p2.wordsuggestor.NGramToNextChoicesMap;
-
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.TreeMap;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-public class NGramToNextChoicesMapTests {
-    private NGramToNextChoicesMap init() {
-        return new NGramToNextChoicesMap(BinarySearchTree::new, BinarySearchTree::new);
-    }
-
-    @Test(timeout = 3000)
-    public void testOneWordPerNGram() {
-        NGramToNextChoicesMap map = init();
-        NGram[] ngrams = new NGram[]{
-                new NGram(new String[]{"foo", "bar", "baz"}),
-                new NGram(new String[]{"fee", "fi", "fo"}),
-                new NGram(new String[]{"a", "s", "d"})
-        };
-
-        String[] words = new String[]{"bop", "fum", "f"};
-        for (int i = 0; i < ngrams.length; i++) {
-            map.seenWordAfterNGram(ngrams[i], words[i]);
-        }
-        for (int i = 0; i < ngrams.length; i++) {
-            Item<String, Integer>[] items = map.getCountsAfter(ngrams[i]);
-            assertEquals(1, items.length);
-            Item<String, Integer> item = items[0];
-            assertEquals(words[i], item.key);
-            assertEquals(1, item.value.intValue());
-        }
-    }
-
-    @Test(timeout = 3000)
-    public void testMultipleWordsPerNGram() {
-        NGramToNextChoicesMap map = init();
-        NGram[] ngrams = new NGram[]{
-                new NGram(new String[]{"foo", "bar", "baz"}),
-                new NGram(new String[]{"fee", "fi", "fo"}),
-                new NGram(new String[]{"four", "score", "and"}),
-                new NGram(new String[]{"3", "2", "2"}),
-                new NGram(new String[]{"a", "s", "d"})
-        };
-
-        String[][] words = new String[][] {
-                new String[]{"bip", "bop", "bzp"},
-                new String[]{"fum", "giants"},
-                new String[]{"ago", "seven", "years"},
-                new String[]{"new", "thrown", "uuu", "zzz"},
-                new String[]{"do", "for", "while"}
-        };
-
-        for (int i = 0; i < ngrams.length; i++) {
-            for (int j = 0; j < words[i].length; j++) {
-                map.seenWordAfterNGram(ngrams[i], words[i][j]);
-            }
-
-        }
-        for (int i = 0; i < ngrams.length; i++) {
-            Item<String, Integer>[] items = map.getCountsAfter(ngrams[i]);
-            String[] answer = words[i];
-            assertEquals(answer.length, items.length);
-            String[] itemsWithoutCounts = new String[items.length];
-            for (int j = 0; j < answer.length; j++) {
-                assertEquals(1, items[j].value.intValue());
-                itemsWithoutCounts[j] = items[j].key;
-            }
-            Arrays.sort(itemsWithoutCounts);
-            assertArrayEquals(answer, itemsWithoutCounts);
-        }
-    }
-
-    @Test(timeout = 3000)
-    public void testGetNonexistentNGram() {
-        NGramToNextChoicesMap map = init();
-        NGram[] ngrams = new NGram[]{
-                new NGram(new String[]{"foo", "bar", "baz"}),
-                new NGram(new String[]{"fee", "fi", "fo"}),
-                new NGram(new String[]{"a", "s", "d"})
-        };
-
-        String[] words = new String[]{"bop", "fum", "f"};
-        for (int i = 0; i < ngrams.length; i++) {
-            map.seenWordAfterNGram(ngrams[i], words[i]);
-        }
-        Item<String, Integer>[] items = map.getCountsAfter(new NGram(new String[] { "yo" }));
-        assertNotNull(items);
-        assertEquals(0, items.length);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(timeout = 3000)
-    public void testRepeatedWordsPerNGram() {
-        NGramToNextChoicesMap map = init();
-        // Creates Ngrams to test for with N = 3
-        NGram[] ngrams = new NGram[]{
-                new NGram(new String[]{"foo", "bar", "baz"}),
-                new NGram(new String[]{"fee", "fi", "fo"}),
-                new NGram(new String[]{"four", "score", "and"}),
-                new NGram(new String[]{"3", "2", "2"}),
-                new NGram(new String[]{"a", "s", "d"})
-        };
-        // Array of words seen after each Ngram with correlating index from above
-        String[][] words = new String[][] {
-                new String[]{"bop", "bip", "boop", "bop", "bop"},
-                new String[]{"fum", "giants", "giants"},
-                new String[]{"seven", "years", "years", "ago", "ago"},
-                new String[]{"throw", "throw", "throw", "throw", "throw"},
-                new String[]{"for", "while", "do", "do", "while", "for"}
-        };
-
-        // yes this is awful, but i can't think of a better way to do it atm
-        // Creates answers for getCountsAfter - Word seen after and count
-        // corrlates with words and ngrams above
-        // Note that words after are in sorted order, not in order of array in words
-        Map<NGram, Item<String, Integer>[]> answers = new TreeMap<>();
-        answers.put(ngrams[0], (Item<String, Integer>[]) new Item[]{
-                new Item<>("bip", 1),
-                new Item<>("boop", 1),
-                new Item<>("bop", 3)
-        });
-
-        answers.put(ngrams[1], (Item<String, Integer>[]) new Item[]{
-                new Item<>("fum", 1),
-                new Item<>("giants", 2)
-        });
-
-        answers.put(ngrams[2], (Item<String, Integer>[]) new Item[]{
-                new Item<>("ago", 2),
-                new Item<>("seven", 1),
-                new Item<>("years", 2)
-        });
-
-        answers.put(ngrams[3], (Item<String, Integer>[]) new Item[]{
-                new Item<>("throw", 5)
-        });
-
-        answers.put(ngrams[4], (Item<String, Integer>[]) new Item[]{
-                new Item<>("do", 2),
-                new Item<>("for", 2),
-                new Item<>("while", 2)
-        });
-
-        // Adds nGrams and words after to student's NGramToNextChoicesMap
-        for (int i = 0; i < ngrams.length; i++) {
-            for (int j = 0; j < words[i].length; j++) {
-                map.seenWordAfterNGram(ngrams[i], words[i][j]);
-            }
-        }
-
-        // checks to see if getCountsAfter returns correctly
-        for (int i = 0; i < ngrams.length; i++) {
-            NGram ngram = ngrams[i];
-            Item<String, Integer>[] results = map.getCountsAfter(ngram);
-            Arrays.sort(results, Comparator.comparing(r -> r.key));
-            Item<String, Integer>[] expected = answers.get(ngram);
-            // checks for correct number of unique words after
-            assertArrayEquals(expected, results);
-        }
-    }
-}
diff --git a/src/tests/gitlab/ckpt1/WorklistGradingTests.java b/src/tests/gitlab/ckpt1/WorklistGradingTests.java
new file mode 100644
index 0000000..c1bb919
--- /dev/null
+++ b/src/tests/gitlab/ckpt1/WorklistGradingTests.java
@@ -0,0 +1,99 @@
+package tests.gitlab.ckpt1;
+
+import cse332.interfaces.worklists.WorkList;
+import org.junit.Test;
+
+import java.util.NoSuchElementException;
+
+import static org.junit.Assert.*;
+
+public abstract class WorklistGradingTests {
+    protected static WorkList<String> STUDENT_STR;
+    protected static WorkList<Double> STUDENT_DOUBLE;
+    protected static WorkList<Integer> STUDENT_INT;
+
+    @Test(timeout = 3000)
+    public void testHasWork() {
+        assertFalse(STUDENT_INT.hasWork());
+    }
+
+    @Test(timeout = 3000)
+    public void testHasWorkAfterAdd() {
+        STUDENT_INT.add(1);
+        assertTrue(STUDENT_INT.hasWork());
+    }
+
+    @Test(timeout = 3000)
+    public void testHasWorkAfterAddRemove() {
+        for (int i = 0; i < 1000; i++) {
+            STUDENT_DOUBLE.add(Math.random());
+        }
+        for (int i = 0; i < 1000; i++) {
+            STUDENT_DOUBLE.next();
+        }
+        assertFalse(STUDENT_DOUBLE.hasWork());
+    }
+    @Test(timeout = 3000)
+    public void testPeekHasException() {
+        assertTrue(doesPeekThrowException(STUDENT_INT));
+
+        addAndRemove(STUDENT_INT, 42, 10);
+        assertTrue(doesPeekThrowException(STUDENT_INT));
+    }
+
+    @Test(timeout = 3000)
+    public void testNextHasException() {
+        assertTrue(doesNextThrowException(STUDENT_INT));
+
+        addAndRemove(STUDENT_INT, 42, 10);
+        assertTrue(doesNextThrowException(STUDENT_INT));
+    }
+    @Test(timeout = 3000)
+    public void testClear() {
+        addAll(STUDENT_STR, new String[]{"Beware", "the", "Jabberwock", "my", "son!"});
+
+        assertTrue(STUDENT_STR.hasWork());
+        assertEquals(5, STUDENT_STR.size());
+
+        STUDENT_STR.clear();
+        assertFalse(STUDENT_STR.hasWork());
+        assertEquals(0, STUDENT_STR.size());
+        assertTrue(doesPeekThrowException(STUDENT_STR));
+        assertTrue(doesNextThrowException(STUDENT_STR));
+    }
+
+    // UTILITY METHODS
+
+    protected static <E> void addAll(WorkList<E> worklist, E[] values) {
+        for (E value : values) {
+            worklist.add(value);
+        }
+    }
+
+    protected static <E> void addAndRemove(WorkList<E> worklist, E value, int amount) {
+        for (int i = 0; i < amount; i++) {
+            worklist.add(value);
+        }
+        for (int i = 0; i < amount; i++) {
+            worklist.next();
+        }
+    }
+
+    protected static <E> boolean doesPeekThrowException(WorkList<E> worklist) {
+        try {
+            worklist.peek();
+        } catch (NoSuchElementException e) {
+            return true;
+        }
+        return false;
+    }
+
+    protected static <E> boolean doesNextThrowException(WorkList<E> worklist) {
+        try {
+            worklist.next();
+        } catch (NoSuchElementException e) {
+            return true;
+        }
+        return false;
+    }
+}
-- 
GitLab