/**
* diqube: Distributed Query Base.
*
* Copyright (C) 2015 Bastian Gloeckle
*
* This file is part of diqube.
*
* diqube is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diqube.data.types.dbl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import org.diqube.data.types.dbl.dict.FpcDoubleDictionary;
import org.diqube.data.types.dbl.dict.FpcPage;
import org.diqube.data.types.dbl.dict.FpcPage.State;
import org.diqube.util.DoubleUtil;
import org.diqube.util.Pair;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
/**
*
* TODO test dict-compare functions with a constant dict, too.
*
* @author Bastian Gloeckle
*/
public class FpcDoubleDictionaryTest {
@Test
public void simpleTest() {
// GIVEN
FpcPage page1 = new FpcPage(0L);
page1.compress(new double[] { 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcDoubleDictionary dict = createDict(0.5, 4.5, page1);
// WHEN/THEN
Assert.assertTrue(DoubleUtil.equals(0.5, dict.decompressValue(0)));
Assert.assertTrue(DoubleUtil.equals(1.5, dict.decompressValue(1)));
Assert.assertTrue(DoubleUtil.equals(2.5, dict.decompressValue(2)));
Assert.assertTrue(DoubleUtil.equals(3.5, dict.decompressValue(3)));
Assert.assertTrue(DoubleUtil.equals(4.5, dict.decompressValue(4)));
Assert.assertEquals(dict.findIdOfValue(0.5), 0);
Assert.assertEquals(dict.findIdOfValue(1.5), 1);
Assert.assertEquals(dict.findIdOfValue(2.5), 2);
Assert.assertEquals(dict.findIdOfValue(3.5), 3);
Assert.assertEquals(dict.findIdOfValue(4.5), 4);
Assert.assertEquals(dict.findIdsOfValues(new Double[] { 0.5, 4.5, 5. }), new Long[] { 0L, 4L, -1L });
Assert.assertTrue(dict.containsAnyValue(new Double[] { 0., 3., 0.5 }));
Assert.assertEquals((long) dict.findLtEqIdOfValue(5.), -(4 + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(4.5), 4);
Assert.assertEquals((long) dict.findLtEqIdOfValue(4.), -(3 + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(1.), -(0 + 1));
Assert.assertNull(dict.findLtEqIdOfValue(0.));
Assert.assertEquals((long) dict.findGtEqIdOfValue(0.), -(0 + 1));
Assert.assertEquals((long) dict.findGtEqIdOfValue(0.5), 0);
Assert.assertEquals((long) dict.findGtEqIdOfValue(1.), -(1 + 1));
Assert.assertNull(dict.findGtEqIdOfValue(5.));
Assert.assertEquals(dict.findIdsOfValuesGt(4.0), new HashSet<>(Arrays.asList(new Long[] { 4L })));
Assert.assertEquals(dict.findIdsOfValuesGt(4.5), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueGt(4.0));
Assert.assertFalse(dict.containsAnyValueGt(4.5));
Assert.assertEquals(dict.findIdsOfValuesGtEq(4.5), new HashSet<>(Arrays.asList(new Long[] { 4L })));
Assert.assertEquals(dict.findIdsOfValuesGtEq(5.0), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueGtEq(4.5));
Assert.assertFalse(dict.containsAnyValueGtEq(5.));
Assert.assertEquals(dict.findIdsOfValuesLt(1.0), new HashSet<>(Arrays.asList(new Long[] { 0L })));
Assert.assertEquals(dict.findIdsOfValuesLt(0.5), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueLt(1.0));
Assert.assertFalse(dict.containsAnyValueLt(0.5));
Assert.assertEquals(dict.findIdsOfValuesLtEq(0.5), new HashSet<>(Arrays.asList(new Long[] { 0L })));
Assert.assertEquals(dict.findIdsOfValuesLtEq(0.4), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueLtEq(0.5));
Assert.assertFalse(dict.containsAnyValueLtEq(0.));
}
@Test
public void twoPageTest() {
// GIVEN
FpcPage page1 = new FpcPage(0L);
State statePage1 = page1.compress(new double[] { 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page2 = new FpcPage(5L, statePage1);
page2.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict = createDict(0.5, 9.5, page1, page2);
// WHEN/THEN
Assert.assertTrue(DoubleUtil.equals(0.5, dict.decompressValue(0)));
Assert.assertTrue(DoubleUtil.equals(1.5, dict.decompressValue(1)));
Assert.assertTrue(DoubleUtil.equals(2.5, dict.decompressValue(2)));
Assert.assertTrue(DoubleUtil.equals(3.5, dict.decompressValue(3)));
Assert.assertTrue(DoubleUtil.equals(4.5, dict.decompressValue(4)));
Assert.assertTrue(DoubleUtil.equals(5.5, dict.decompressValue(5)));
Assert.assertTrue(DoubleUtil.equals(6.5, dict.decompressValue(6)));
Assert.assertTrue(DoubleUtil.equals(7.5, dict.decompressValue(7)));
Assert.assertTrue(DoubleUtil.equals(8.5, dict.decompressValue(8)));
Assert.assertTrue(DoubleUtil.equals(9.5, dict.decompressValue(9)));
Assert.assertEquals(dict.findIdOfValue(0.5), 0);
Assert.assertEquals(dict.findIdOfValue(1.5), 1);
Assert.assertEquals(dict.findIdOfValue(2.5), 2);
Assert.assertEquals(dict.findIdOfValue(3.5), 3);
Assert.assertEquals(dict.findIdOfValue(4.5), 4);
Assert.assertEquals(dict.findIdOfValue(5.5), 5);
Assert.assertEquals(dict.findIdOfValue(6.5), 6);
Assert.assertEquals(dict.findIdOfValue(7.5), 7);
Assert.assertEquals(dict.findIdOfValue(8.5), 8);
Assert.assertEquals(dict.findIdOfValue(9.5), 9);
Assert.assertEquals(dict.findIdsOfValues(new Double[] { 5.5, 4.4, 5. }), new Long[] { 5L, -1L, -1L });
Assert.assertTrue(dict.containsAnyValue(new Double[] { 0., 3., 9.5 }));
Assert.assertEquals((long) dict.findLtEqIdOfValue(5.), -(4 + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(4.5), 4);
Assert.assertEquals((long) dict.findLtEqIdOfValue(4.), -(3 + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(1.), -(0 + 1));
Assert.assertNull(dict.findLtEqIdOfValue(0.));
Assert.assertEquals((long) dict.findGtEqIdOfValue(0.), -(0 + 1));
Assert.assertEquals((long) dict.findGtEqIdOfValue(0.5), 0);
Assert.assertEquals((long) dict.findGtEqIdOfValue(1.), -(1 + 1));
Assert.assertEquals((long) dict.findGtEqIdOfValue(5.), -(5 + 1));
Assert.assertNull(dict.findGtEqIdOfValue(9.6));
Assert.assertEquals(dict.findIdsOfValuesGt(4.0),
new HashSet<>(Arrays.asList(new Long[] { 4L, 5L, 6L, 7L, 8L, 9L })));
Assert.assertEquals(dict.findIdsOfValuesGt(4.5), new HashSet<>(Arrays.asList(new Long[] { 5L, 6L, 7L, 8L, 9L })));
Assert.assertEquals(dict.findIdsOfValuesGt(9.5), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueGt(4.5));
Assert.assertFalse(dict.containsAnyValueGt(9.5));
Assert.assertEquals(dict.findIdsOfValuesGtEq(4.5),
new HashSet<>(Arrays.asList(new Long[] { 4L, 5L, 6L, 7L, 8L, 9L })));
Assert.assertEquals(dict.findIdsOfValuesGtEq(4.6), new HashSet<>(Arrays.asList(new Long[] { 5L, 6L, 7L, 8L, 9L })));
Assert.assertTrue(dict.containsAnyValueGtEq(9.5));
Assert.assertFalse(dict.containsAnyValueGtEq(9.6));
Assert.assertEquals(dict.findIdsOfValuesLt(5.5), new HashSet<>(Arrays.asList(new Long[] { 0L, 1L, 2L, 3L, 4L })));
Assert.assertEquals(dict.findIdsOfValuesLt(1.0), new HashSet<>(Arrays.asList(new Long[] { 0L })));
Assert.assertEquals(dict.findIdsOfValuesLt(0.5), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueLt(5.5));
Assert.assertTrue(dict.containsAnyValueLt(1.0));
Assert.assertFalse(dict.containsAnyValueLt(0.5));
Assert.assertEquals(dict.findIdsOfValuesLtEq(5.4), new HashSet<>(Arrays.asList(new Long[] { 0L, 1L, 2L, 3L, 4L })));
Assert.assertEquals(dict.findIdsOfValuesLtEq(0.5), new HashSet<>(Arrays.asList(new Long[] { 0L })));
Assert.assertEquals(dict.findIdsOfValuesLtEq(0.4), new HashSet<>(Arrays.asList(new Long[] {})));
Assert.assertTrue(dict.containsAnyValueLtEq(0.5));
Assert.assertTrue(dict.containsAnyValueLtEq(5.4));
Assert.assertFalse(dict.containsAnyValueLtEq(0.));
}
@Test
public void largeTwoPageTest() {
// GIVEN
FpcPage page1 = new FpcPage(0L);
// get somewhat "randomly" (but reconstructably) distributed numbers -> use Fibonacci numbers divided by 10
double[] fib1 = new double[500];
fib1[0] = 0.1;
fib1[1] = 0.1;
for (int i = 2; i < fib1.length; i++)
fib1[i] = fib1[i - 1] + fib1[i - 2];
double[] fib2 = new double[500];
fib2[0] = fib1[fib1.length - 2] + fib1[fib1.length - 1];
fib2[1] = fib1[fib1.length - 1] + fib2[0];
for (int i = 2; i < fib2.length; i++)
fib2[i] = fib2[i - 1] + fib2[i - 2];
State statePage1 = page1.compress(fib1);
FpcPage page2 = new FpcPage(fib1.length, statePage1);
page2.compress(fib2);
FpcDoubleDictionary dict = createDict(fib1[0], fib2[fib2.length - 1], page1, page2);
// WHEN/THEN
Assert.assertTrue(DoubleUtil.equals(fib1[fib1.length - 1], dict.decompressValue(fib1.length - 1)));
Assert.assertTrue(DoubleUtil.equals(fib2[0], dict.decompressValue(fib1.length)));
Assert.assertEquals(dict.findIdOfValue(fib2[0]), fib1.length);
Assert.assertEquals(dict.findIdOfValue(fib2[fib2.length - 1]), fib1.length + fib2.length - 1);
double beforeLast = fib2[fib2.length - 2] + ((fib2[fib2.length - 1] - fib2[fib2.length - 2]) / 2);
Assert.assertEquals((long) dict.findGtEqIdOfValue(beforeLast), -(fib1.length + fib2.length - 1 + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(beforeLast), -(fib1.length + fib2.length - 2 + 1));
double middle = fib1[fib1.length - 1] + ((fib2[0] - fib1[fib1.length - 1]) / 2);
Assert.assertEquals((long) dict.findGtEqIdOfValue(middle), -(fib1.length + 1));
Assert.assertEquals((long) dict.findLtEqIdOfValue(middle), -(fib1.length - 1 + 1));
}
@Test
public void compareEqualIdsTest1() {
// GIVEN
// 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
FpcPage page11 = new FpcPage(0L);
State statePage11 = page11.compress(new double[] { 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page12 = new FpcPage(5L, statePage11);
page12.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict1 = createDict(0.5, 9.5, page11, page12);
// 1., 1.4, 1.5, 4., 4.4, 4.8, 6.5, 100.
FpcPage page21 = new FpcPage(0L);
State statePage21 = page21.compress(new double[] { 1., 1.4, 1.5, 4. });
FpcPage page22 = new FpcPage(4L, statePage21);
page22.compress(new double[] { 4.4, 4.8, 6.5, 100. });
FpcDoubleDictionary dict2 = createDict(1., 100., page21, page22);
// WHEN
Map<Long, Long> eqIds = dict1.findEqualIds(dict2);
Map<Long, Long> expected = new HashMap<>();
expected.put(1L, 2L);
expected.put(6L, 6L);
Assert.assertEquals(eqIds, expected);
expected = HashBiMap.create(expected).inverse();
eqIds = dict2.findEqualIds(dict1);
Assert.assertEquals(eqIds, expected);
}
@Test
public void compareEqualIdsTest2() {
// GIVEN
// 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
FpcPage page11 = new FpcPage(0L);
State statePage11 = page11.compress(new double[] { 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page12 = new FpcPage(5L, statePage11);
page12.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict1 = createDict(0.5, 9.5, page11, page12);
// .5, 1.4, 1.5, 4., 4.4, 4.8, 6.5, 9.5
FpcPage page21 = new FpcPage(0L);
State statePage21 = page21.compress(new double[] { .5, 1.4, 1.5, 4. });
FpcPage page22 = new FpcPage(4L, statePage21);
page22.compress(new double[] { 4.4, 4.8, 6.5, 9.5 });
FpcDoubleDictionary dict2 = createDict(.5, 9.5, page21, page22);
// WHEN
Map<Long, Long> eqIds = dict1.findEqualIds(dict2);
Map<Long, Long> expected = new HashMap<>();
expected.put(0L, 0L);
expected.put(1L, 2L);
expected.put(6L, 6L);
expected.put(9L, 7L);
Assert.assertEquals(eqIds, expected);
expected = HashBiMap.create(expected).inverse();
eqIds = dict2.findEqualIds(dict1);
Assert.assertEquals(eqIds, expected);
}
@Test
public void compareLtEqIdsTest1() {
// GIVEN
// 0.4, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
FpcPage page11 = new FpcPage(0L);
State statePage11 = page11.compress(new double[] { 0.4, 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page12 = new FpcPage(6L, statePage11);
page12.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict1 = createDict(0.5, 9.5, page11, page12);
// .5, 1.4, 1.5, 4., 4.4, 4.8, 6.5, 9.5, 10.
FpcPage page21 = new FpcPage(0L);
State statePage21 = page21.compress(new double[] { .5, 1.4, 1.5, 4. });
FpcPage page22 = new FpcPage(4L, statePage21);
page22.compress(new double[] { 4.4, 4.8, 6.5, 9.5, 10. });
FpcDoubleDictionary dict2 = createDict(.5, 9.5, page21, page22);
// WHEN
Map<Long, Long> ltEqIds = dict1.findLtEqIds(dict2);
Map<Long, Long> expected = new HashMap<>();
expected.put(0L, -(0 + 1L));
expected.put(1L, 0L);
expected.put(2L, 2L);
expected.put(3L, -(3 + 1L));
expected.put(4L, -(3 + 1L));
expected.put(5L, -(5 + 1L));
expected.put(6L, -(6 + 1L));
expected.put(7L, 6L);
expected.put(8L, -(7 + 1L));
expected.put(9L, -(7 + 1L));
expected.put(10L, 7L);
Assert.assertEquals(ltEqIds, expected);
expected = new HashMap<>();
expected.put(0L, 1L);
expected.put(1L, -(2 + 1L));
expected.put(2L, 2L);
expected.put(3L, -(5 + 1L));
expected.put(4L, -(5 + 1L));
expected.put(5L, -(6 + 1L));
expected.put(6L, 7L);
expected.put(7L, 10L);
ltEqIds = dict2.findLtEqIds(dict1);
Assert.assertEquals(ltEqIds, expected);
}
@Test
public void compareGtEqIdsTest1() {
// GIVEN
// 0.4, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
FpcPage page11 = new FpcPage(0L);
State statePage11 = page11.compress(new double[] { 0.4, 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page12 = new FpcPage(6L, statePage11);
page12.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict1 = createDict(0.5, 9.5, page11, page12);
// .5, 1.4, 1.5, 4., 4.4, 4.8, 6.5, 9.5, 10.
FpcPage page21 = new FpcPage(0L);
State statePage21 = page21.compress(new double[] { .5, 1.4, 1.5, 4. });
FpcPage page22 = new FpcPage(4L, statePage21);
page22.compress(new double[] { 4.4, 4.8, 6.5, 9.5, 10. });
FpcDoubleDictionary dict2 = createDict(.5, 9.5, page21, page22);
// WHEN
Map<Long, Long> gtEqIds = dict1.findGtEqIds(dict2);
Map<Long, Long> expected = new HashMap<>();
expected.put(1L, 0L);
expected.put(2L, 2L);
expected.put(3L, -(2 + 1L));
expected.put(4L, -(2 + 1L));
expected.put(5L, -(4 + 1L));
expected.put(6L, -(5 + 1L));
expected.put(7L, 6L);
expected.put(8L, -(6 + 1L));
expected.put(9L, -(6 + 1L));
expected.put(10L, 7L);
Assert.assertEquals(gtEqIds, expected);
expected = new HashMap<>();
expected.put(0L, 1L);
expected.put(1L, -(1 + 1L));
expected.put(2L, 2L);
expected.put(3L, -(4 + 1L));
expected.put(4L, -(4 + 1L));
expected.put(5L, -(5 + 1L));
expected.put(6L, 7L);
expected.put(7L, 10L);
expected.put(8L, -(10 + 1L));
gtEqIds = dict2.findGtEqIds(dict1);
Assert.assertEquals(gtEqIds, expected);
}
@Test
public void twoPageIteratorTest() {
// GIVEN
FpcPage page1 = new FpcPage(0L);
State statePage1 = page1.compress(new double[] { 0.5, 1.5, 2.5, 3.5, 4.5 });
FpcPage page2 = new FpcPage(5L, statePage1);
page2.compress(new double[] { 5.5, 6.5, 7.5, 8.5, 9.5 });
FpcDoubleDictionary dict = createDict(0.5, 9.5, page1, page2);
// THEN
List<Double> expectedValues = new ArrayList<>(Arrays.asList(0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5));
List<Pair<Long, Double>> expected = new ArrayList<>();
for (long i = 0; i < expectedValues.size(); i++)
expected.add(new Pair<>(i, expectedValues.get((int) i)));
Assert.assertEquals(Lists.newArrayList(dict.iterator()), expected,
"Expected that iterator returns correct elements.");
}
private FpcDoubleDictionary createDict(double lowestValue, double highestValue, FpcPage... pages) {
NavigableMap<Long, FpcPage> pagesMap = new TreeMap<>();
for (FpcPage page : pages)
pagesMap.put(page.getFirstId(), page);
return new FpcDoubleDictionary(pagesMap, lowestValue, highestValue);
}
}