kopia lustrzana https://github.com/onthegomap/planetiler
401 wiersze
10 KiB
Java
401 wiersze
10 KiB
Java
/*
|
|
* Licensed to GraphHopper GmbH under one or more contributor
|
|
* license agreements. See the NOTICE file distributed with this work for
|
|
* additional information regarding copyright ownership.
|
|
*
|
|
* GraphHopper GmbH licenses this file to you under the Apache License,
|
|
* Version 2.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.onthegomap.planetiler.collection;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
import com.carrotsearch.hppc.IntArrayList;
|
|
import com.carrotsearch.hppc.IntHashSet;
|
|
import com.carrotsearch.hppc.IntSet;
|
|
import java.util.PriorityQueue;
|
|
import java.util.Random;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.CsvSource;
|
|
|
|
|
|
/**
|
|
* Ported from <a href=
|
|
* "https://github.com/graphhopper/graphhopper/blob/master/core/src/test/java/com/graphhopper/coll/MinHeapWithUpdateTest.java">GraphHopper</a>
|
|
* and modified to use long instead of float values, use stable random seed for reproducibility, and to use new
|
|
* implementations.
|
|
*/
|
|
class LongMinHeapTest {
|
|
|
|
protected LongMinHeap heap;
|
|
|
|
void create(int capacity) {
|
|
heap = LongMinHeap.newArrayHeap(capacity, Integer::compare);
|
|
}
|
|
|
|
@Test
|
|
void outOfRange() {
|
|
create(4);
|
|
assertThrows(IllegalArgumentException.class, () -> heap.push(4, 12L));
|
|
assertThrows(IllegalArgumentException.class, () -> heap.push(-1, 12L));
|
|
}
|
|
|
|
@Test
|
|
void tooManyElements() {
|
|
create(3);
|
|
heap.push(1, 1L);
|
|
heap.push(2, 1L);
|
|
heap.push(0, 1L);
|
|
// pushing element 1 again is not allowed (but this is not checked explicitly). however pushing more elements
|
|
// than 3 is already an error
|
|
assertThrows(IllegalStateException.class, () -> heap.push(1, 1L));
|
|
assertThrows(IllegalStateException.class, () -> heap.push(2, 61L));
|
|
}
|
|
|
|
@Test
|
|
void duplicateElements() {
|
|
create(5);
|
|
heap.push(1, 2L);
|
|
heap.push(0, 4L);
|
|
heap.push(2, 1L);
|
|
assertEquals(2, heap.poll());
|
|
// pushing 2 again is ok because it was polled before
|
|
heap.push(2, 6L);
|
|
// but now its not ok to push it again
|
|
assertThrows(IllegalStateException.class, () -> heap.push(2, 4L));
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@CsvSource({
|
|
"0, 1, 2, 3, 4, 5, 6, 7",
|
|
"7, 6, 5, 4, 3, 2, 1, 0",
|
|
"0, 1, 2, 6, 7, 5, 4, 3",
|
|
"0, 1, 5, 2, 4, 3, 6, 7",
|
|
"0, 5, 6, 7, 1, 2, 4, 3",
|
|
"5, 0, 1, 2, 7, 6, 4, 3",
|
|
})
|
|
void tieBreaker(int a, int b, int c, int d, int e, int f, int g, int h) {
|
|
heap = LongMinHeap.newArrayHeap(9, (id1, id2) -> -Integer.compare(id1, id2));
|
|
heap.push(a, 0L);
|
|
heap.push(b, 0L);
|
|
heap.push(c, 0L);
|
|
heap.push(d, 0L);
|
|
heap.push(e, 0L);
|
|
heap.push(f, 0L);
|
|
heap.push(g, 0L);
|
|
heap.push(h, 0L);
|
|
assertEquals(7, heap.poll());
|
|
assertEquals(6, heap.poll());
|
|
assertEquals(5, heap.poll());
|
|
assertEquals(4, heap.poll());
|
|
assertEquals(3, heap.poll());
|
|
assertEquals(2, heap.poll());
|
|
assertEquals(1, heap.poll());
|
|
assertEquals(0, heap.poll());
|
|
}
|
|
|
|
@Test
|
|
void testContains() {
|
|
create(4);
|
|
heap.push(1, 1L);
|
|
heap.push(2, 7L);
|
|
heap.push(0, 5L);
|
|
assertFalse(heap.contains(3));
|
|
assertTrue(heap.contains(1));
|
|
assertEquals(1, heap.poll());
|
|
assertFalse(heap.contains(1));
|
|
}
|
|
|
|
@Test
|
|
void containsAfterClear() {
|
|
create(4);
|
|
heap.push(1, 1L);
|
|
heap.push(2, 1L);
|
|
assertEquals(2, heap.size());
|
|
heap.clear();
|
|
assertFalse(heap.contains(0));
|
|
assertFalse(heap.contains(1));
|
|
assertFalse(heap.contains(2));
|
|
}
|
|
|
|
|
|
@Test
|
|
void testSize() {
|
|
create(10);
|
|
assertEquals(0, heap.size());
|
|
assertTrue(heap.isEmpty());
|
|
heap.push(9, 36L);
|
|
heap.push(5, 23L);
|
|
heap.push(3, 23L);
|
|
assertEquals(3, heap.size());
|
|
assertFalse(heap.isEmpty());
|
|
}
|
|
|
|
@Test
|
|
void testClear() {
|
|
create(5);
|
|
assertTrue(heap.isEmpty());
|
|
heap.push(3, 12L);
|
|
heap.push(4, 3L);
|
|
assertEquals(2, heap.size());
|
|
heap.clear();
|
|
assertTrue(heap.isEmpty());
|
|
|
|
heap.push(4, 63L);
|
|
heap.push(1, 21L);
|
|
assertEquals(2, heap.size());
|
|
assertEquals(1, heap.peekId());
|
|
assertEquals(21L, heap.peekValue());
|
|
assertEquals(1, heap.poll());
|
|
assertEquals(4, heap.poll());
|
|
assertTrue(heap.isEmpty());
|
|
}
|
|
|
|
@Test
|
|
void testPush() {
|
|
create(5);
|
|
|
|
heap.push(4, 63L);
|
|
heap.push(1, 21L);
|
|
assertEquals(2, heap.size());
|
|
assertEquals(1, heap.peekId());
|
|
assertEquals(21L, heap.peekValue());
|
|
assertEquals(1, heap.poll());
|
|
assertEquals(4, heap.poll());
|
|
assertTrue(heap.isEmpty());
|
|
}
|
|
|
|
@Test
|
|
void testPeek() {
|
|
create(5);
|
|
heap.push(4, -16L);
|
|
heap.push(2, 13L);
|
|
heap.push(1, -51L);
|
|
heap.push(3, 4L);
|
|
assertEquals(1, heap.peekId());
|
|
assertEquals(-51L, heap.peekValue());
|
|
}
|
|
|
|
@Test
|
|
void pushAndPoll() {
|
|
create(10);
|
|
heap.push(9, 36L);
|
|
heap.push(5, 23L);
|
|
heap.push(3, 23L);
|
|
assertEquals(3, heap.size());
|
|
heap.poll();
|
|
assertEquals(2, heap.size());
|
|
heap.poll();
|
|
heap.poll();
|
|
assertTrue(heap.isEmpty());
|
|
}
|
|
|
|
@Test
|
|
void pollSorted() {
|
|
create(10);
|
|
heap.push(9, 36L);
|
|
heap.push(5, 21L);
|
|
heap.push(3, 23L);
|
|
heap.push(8, 57L);
|
|
heap.push(7, 22L);
|
|
IntArrayList polled = new IntArrayList();
|
|
while (!heap.isEmpty()) {
|
|
polled.add(heap.poll());
|
|
}
|
|
assertEquals(IntArrayList.from(5, 7, 3, 9, 8), polled);
|
|
}
|
|
|
|
@Test
|
|
void poll() {
|
|
create(10);
|
|
assertTrue(heap.isEmpty());
|
|
assertEquals(0, heap.size());
|
|
|
|
heap.push(9, 36L);
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(1, heap.size());
|
|
|
|
heap.push(5, 21L);
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(2, heap.size());
|
|
|
|
heap.push(3, 23L);
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(3, heap.size());
|
|
|
|
heap.push(8, 57L);
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(4, heap.size());
|
|
|
|
assertEquals(5, heap.poll());
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(3, heap.size());
|
|
|
|
assertEquals(3, heap.poll());
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(2, heap.size());
|
|
|
|
assertEquals(9, heap.poll());
|
|
assertFalse(heap.isEmpty());
|
|
assertEquals(1, heap.size());
|
|
|
|
assertEquals(8, heap.poll());
|
|
assertTrue(heap.isEmpty());
|
|
assertEquals(0, heap.size());
|
|
}
|
|
|
|
@Test
|
|
void clear() {
|
|
create(10);
|
|
heap.push(9, 36L);
|
|
heap.push(5, 21L);
|
|
heap.push(3, 23L);
|
|
heap.clear();
|
|
assertTrue(heap.isEmpty());
|
|
assertEquals(0, heap.size());
|
|
}
|
|
|
|
@Test
|
|
void poll100Ascending() {
|
|
create(100);
|
|
for (int i = 1; i < 100; i++) {
|
|
heap.push(i, i);
|
|
}
|
|
for (int i = 1; i < 100; i++) {
|
|
assertEquals(i, heap.poll());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
void poll100Descending() {
|
|
create(100);
|
|
for (int i = 99; i >= 1; i--) {
|
|
heap.push(i, i);
|
|
}
|
|
for (int i = 1; i < 100; i++) {
|
|
assertEquals(i, heap.poll());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
void update() {
|
|
create(10);
|
|
heap.push(9, 36L);
|
|
heap.push(5, 21L);
|
|
heap.push(3, 23L);
|
|
heap.update(3, 1L);
|
|
assertEquals(3, heap.peekId());
|
|
heap.update(3, 100L);
|
|
assertEquals(5, heap.peekId());
|
|
heap.update(9, -13L);
|
|
assertEquals(9, heap.peekId());
|
|
assertEquals(-13L, heap.peekValue());
|
|
IntArrayList polled = new IntArrayList();
|
|
while (!heap.isEmpty()) {
|
|
polled.add(heap.poll());
|
|
}
|
|
assertEquals(IntArrayList.from(9, 5, 3), polled);
|
|
}
|
|
|
|
@Test
|
|
void updateHead() {
|
|
create(10);
|
|
heap.push(1, 1);
|
|
heap.push(2, 2);
|
|
heap.push(3, 3);
|
|
heap.push(4, 4);
|
|
heap.push(5, 5);
|
|
heap.updateHead(6);
|
|
heap.updateHead(7);
|
|
heap.updateHead(8);
|
|
|
|
IntArrayList polled = new IntArrayList();
|
|
while (!heap.isEmpty()) {
|
|
polled.add(heap.poll());
|
|
}
|
|
assertEquals(IntArrayList.from(4, 5, 1, 2, 3), polled);
|
|
}
|
|
|
|
@Test
|
|
void randomPushsThenPolls() {
|
|
Random rnd = new Random(0);
|
|
int size = 1 + rnd.nextInt(100);
|
|
PriorityQueue<Entry> pq = new PriorityQueue<>(size);
|
|
create(size);
|
|
IntSet set = new IntHashSet();
|
|
while (pq.size() < size) {
|
|
int id = rnd.nextInt(size);
|
|
if (!set.add(id))
|
|
continue;
|
|
long val = (long) (Long.MAX_VALUE * rnd.nextFloat());
|
|
pq.add(new Entry(id, val));
|
|
heap.push(id, val);
|
|
}
|
|
while (!pq.isEmpty()) {
|
|
Entry entry = pq.poll();
|
|
assertEquals(entry.val, heap.peekValue());
|
|
assertEquals(entry.id, heap.poll());
|
|
assertEquals(pq.size(), heap.size());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
void randomPushsAndPolls() {
|
|
Random rnd = new Random(0);
|
|
int size = 1 + rnd.nextInt(100);
|
|
PriorityQueue<Entry> pq = new PriorityQueue<>(size);
|
|
create(size);
|
|
IntSet set = new IntHashSet();
|
|
int pushCount = 0;
|
|
for (int i = 0; i < 1000; i++) {
|
|
boolean push = pq.isEmpty() || (rnd.nextBoolean());
|
|
if (push) {
|
|
int id = rnd.nextInt(size);
|
|
if (!set.add(id))
|
|
continue;
|
|
long val = (long) (Long.MAX_VALUE * rnd.nextFloat());
|
|
pq.add(new Entry(id, val));
|
|
heap.push(id, val);
|
|
pushCount++;
|
|
} else {
|
|
Entry entry = pq.poll();
|
|
assert entry != null;
|
|
assertEquals(entry.val, heap.peekValue());
|
|
assertEquals(entry.id, heap.poll());
|
|
assertEquals(pq.size(), heap.size());
|
|
set.removeAll(entry.id);
|
|
}
|
|
}
|
|
assertTrue(pushCount > 0);
|
|
}
|
|
|
|
static class Entry implements Comparable<Entry> {
|
|
int id;
|
|
long val;
|
|
|
|
public Entry(int id, long val) {
|
|
this.id = id;
|
|
this.val = val;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(Entry o) {
|
|
return Long.compare(val, o.val);
|
|
}
|
|
}
|
|
}
|