/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.opentripplanner.common.pqueue; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; import junit.framework.TestCase; /* * Test correctness and relative speed of various * priority queue implementations. */ public class TestPQueues extends TestCase { private static final int N = 200000; private static final int ITER = 2; private static final int INNER_ITER = 10; public void doQueue(OTPPriorityQueue<Integer> q, List<Integer> input, List<Integer> expected) { List<Integer> result = new ArrayList<Integer>(N); int expectedSum = 0; for (Integer i : input) { q.insert(i, i * 0.5); expectedSum += i; } while (!q.empty()) { result.add(q.extract_min()); } assertEquals(result, expected); // check behavior when queue is empty assertEquals(q.size(), 0); assertNull(q.peek_min()); assertNull(q.extract_min()); q.insert(100, 10); q.insert(200, 20); assertEquals(q.size(), 2); assertNotNull(q.extract_min()); assertNotNull(q.extract_min()); assertNull(q.extract_min()); assertEquals(q.size(), 0); // fill and empty the queue a few times long t0 = System.currentTimeMillis(); for (int iter = 0; iter < INNER_ITER; iter++) { int sum = 0; for (Integer i : input) q.insert(i, i); while (!q.empty()) sum += q.extract_min(); // keep compiler from optimizing out extract assertTrue(sum == expectedSum); } long t1 = System.currentTimeMillis(); System.out.println(q.getClass() + " \ttime " + (t1-t0)/1000.0 + " sec"); } public void fillQueue(OTPPriorityQueue<Integer> q, List<Integer> input) { long t0 = System.currentTimeMillis(); for (Integer i : input) { q.insert(i, i * 0.5); } int sum = 0; for (int i=0; i<INNER_ITER; i++) { for (Integer j : input) { sum += q.extract_min(); q.insert(j, j * 0.5); } } while (!q.empty()) { sum += q.extract_min(); } // keep compiler from optimizing out extract assertTrue(sum != 0); long t1 = System.currentTimeMillis(); System.out.println(q.getClass() + " time " + (t1 - t0) / 1000.0 + " sec"); } public void testIntBinHeap() { IntBinHeap binHeap = new IntBinHeap(100); binHeap.insert(0, 123); assertEquals(123, binHeap.peek_min_key(), 1e-4); assertEquals(1, binHeap.size()); binHeap.rekey(0, 12); assertEquals(12, binHeap.peek_min_key(), 1e-4); assertEquals(1, binHeap.size()); // element 8 is not present binHeap.rekey(8, 8); assertEquals(12, binHeap.peek_min_key(), 1e-4); assertEquals(1, binHeap.size()); } private List<OTPPriorityQueue<Integer>> makeQueues() { List<OTPPriorityQueue<Integer>> queues = new ArrayList<OTPPriorityQueue<Integer>>(); queues.add(new PriorityQueueImpl<Integer>()); // commented out to avoid slow testing // queues.add(new FibHeap<Integer>(N)); queues.add(new BinHeap<Integer>(N)); queues.add(new IntBinHeap(N)); queues.add(new BinHeap<Integer>(10)); queues.add(new IntBinHeap(10)); return queues; } public void testCompareHeaps() throws InterruptedException { List<Integer> input, expected; input = new ArrayList<Integer>(N); for (int i=0; i<N; i++) input.add((int) (Math.random() * 10000)); System.out.println("\ninsert/extract " + N + " Integers " + INNER_ITER + " times"); expected = new ArrayList<Integer>(N); PriorityQueue<Integer> q = new PriorityQueue<Integer>(N); for (Integer j : input) q.add(j); while (!q.isEmpty()) expected.add(q.remove()); System.out.println(q.getClass() + " (expected results)"); for (int i=0; i<ITER; i++) { for (OTPPriorityQueue<Integer> queue : makeQueues()) { doQueue(queue, input, expected); } } System.out.println("\nmaintain queue at size " + N); for (OTPPriorityQueue<Integer> queue : makeQueues()) { fillQueue(queue, input); } } /* * You must be careful to produce unique objects for rekeying, * otherwise the same object might be rekeyed twice or more. */ public void testRekey() throws InterruptedException { final int N = 50000; final int ITER = 2; List<Double> keys; List<Integer> vals; keys = new ArrayList<Double>(N); vals = new ArrayList<Integer>(N); BinHeap<Integer> bh = new BinHeap<Integer>(20); for (int iter = 0; iter < ITER; iter++) { // reuse internal array in binheap bh.reset(); // fill both keys and values with random numbers for (int i=0; i<N; i++) { keys.add(i, (Math.random() * 10000)); vals.add(i, (N - i) * 3); } // insert them into the queue for (int i=0; i<N; i++) { bh.insert(vals.get(i), keys.get(i)); //bh.dump(); } // requeue every item with a new key that is an // order-preserving function of its place in the original list System.out.printf("\nRekey %d elements\n", N); long t0 = System.currentTimeMillis(); for (int i=0; i<N; i++) { bh.rekey(vals.get(i), i * 2.0D + 10); // bh.dump(); } long t1 = System.currentTimeMillis(); double tSec = (t1-t0)/1000.0; System.out.printf("time %f sec\n", tSec); System.out.printf("time per rekey %f\n", tSec / N); // pull everything out of the queue in order // and check that the order matches the original list System.out.printf("Comparing to expected results\n"); for (int i=0; i<N; i++) { Double qp = bh.peek_min_key(); Integer qi = bh.extract_min(); //System.out.printf("%3d : queue key %f queue val %d expected %d\n", i, qp, qi, vals.get(i)); assertEquals(qi, vals.get(i)); } // the queue should be empty at the end of each iteration assertTrue(bh.empty()); } } }