package org.wikibrain.spatial.distance; import com.vividsolutions.jts.geom.*; import org.junit.Ignore; import org.junit.Test; import org.wikibrain.core.dao.DaoException; import org.wikibrain.spatial.constants.Precision; import org.wikibrain.spatial.dao.SpatialDataDao; import org.wikibrain.spatial.util.WikiBrainSpatialUtils; import org.wikibrain.utils.Scoreboard; import java.util.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * @author Shilad Sen */ public class TestSphereDistanceMetric { private Random random = new Random(); private GeometryFactory factory = new GeometryFactory(new PrecisionModel(),8307); @Ignore @Test public void testKnnManyTimes() throws DaoException { for (int i= 0; i < 100; i++) { testKnn(); } } @Test public void testKnn() throws DaoException { int numNeighbors = 100; Point query = makePoint(); Scoreboard<Point> actual = new Scoreboard<Point>(numNeighbors, Scoreboard.Order.INCREASING); Map<Integer, Geometry> points = new HashMap<Integer, Geometry>(); for (int i = 0; i < 100000; i++) { Point p = makePoint(); points.put(i * 3, p); actual.add(p, WikiBrainSpatialUtils.haversine(query, p)); } SpatialDataDao dao = mock(SpatialDataDao.class); when(dao.getAllGeometriesInLayer("wikidata", Precision.LatLonPrecision.HIGH)) .thenReturn(points); SphericalDistanceMetric metric = new SphericalDistanceMetric(dao); metric.enableCache(true); System.out.println("Closest points to " + query + " are: "); long before = System.currentTimeMillis(); List<SpatialDistanceMetric.Neighbor> neighbors = metric.getNeighbors(query, numNeighbors); long after = System.currentTimeMillis(); System.err.println("elapsed millis is " + (after - before)); for (int i = 0; i < neighbors.size(); i++) { SpatialDistanceMetric.Neighbor n = neighbors.get(i); Point p = actual.getElement(i); assertSame(p, points.get(n.conceptId)); System.out.println("\t" + points.get(n.conceptId) + " with distance " + n.distance); } } @Test public void testMatrix() throws DaoException { SpatialDataDao dao = mock(SpatialDataDao.class); when(dao.getAllGeometriesInLayer("wikidata", Precision.LatLonPrecision.HIGH)) .thenReturn(new HashMap<Integer, Geometry>()); SphericalDistanceMetric metric = new SphericalDistanceMetric(dao); metric.enableCache(true); List<Geometry> cols = new ArrayList<Geometry>(); List<Geometry> rows = new ArrayList<Geometry>(); for (int i = 0; i < 10; i++) { cols.add(makePoint()); } for (int i = 0; i < 5; i++) { rows.add(makePoint()); } float [][] distance = metric.distance(rows, cols); for (int i = 0; i < cols.size(); i++) { for (int j = 0; j < rows.size(); j++) { System.err.println("i " +i + ", j " + j); assertEquals(metric.distance(rows.get(j), cols.get(i)), distance[j][i], 1.5); } } } private Point makePoint() { double lat = 90 - random.nextDouble() * 180; double lon = 180 - random.nextDouble() * 360; return factory.createPoint(new Coordinate(lon, lat)); } @Test public void testSphereOrdering() { // Make sure ordering for euclidean and spherical distances are consistent. for (int i = 0; i < 10000; i++) { Point p1 = makePoint(); Point p2 = makePoint(); Point p3 = makePoint(); double d12 = WikiBrainSpatialUtils.haversine(p1, p2); double d13 = WikiBrainSpatialUtils.haversine(p1, p3); double d23 = WikiBrainSpatialUtils.haversine(p2, p3); double e12 = euclidean(p1, p2); double e13 = euclidean(p1, p3); double e23 = euclidean(p2, p3); assert((d12 > d13) == (e12 > e13)); assert((d12 > d23) == (e12 > e23)); assert((d13 > d23) == (e13 > e23)); } } private double euclidean(Point p1, Point p2) { double [] c1 = WikiBrainSpatialUtils.get3DPoints(p1); double [] c2 = WikiBrainSpatialUtils.get3DPoints(p2); return Math.sqrt( (c1[0] - c2[0]) * (c1[0] - c2[0]) + (c1[1] - c2[1]) * (c1[1] - c2[1]) + (c1[2] - c2[2]) * (c1[2] - c2[2]) ); } @Test public void benchHaversine() { double sum = 0.0; long before = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { Point p1 = makePoint(); Point p2 = makePoint(); sum += WikiBrainSpatialUtils.haversine(p1.getX(), p1.getY(), p2.getX(), p2.getY()); } long after = System.currentTimeMillis(); System.err.println("elapsed is " + (after-before)); } }