/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library 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;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotools.graph.util.delaunay;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import org.geotools.filter.Expression;
import org.geotools.graph.structure.Graph;
import org.geotools.graph.structure.basic.BasicGraph;
import org.opengis.feature.simple.SimpleFeature;
/**
*
* @author jfc173
*
* @source $URL$
*/
public class PoissonClusterer {
private static double threshold = 1.0E-10;
/** Creates a new instance of PoissonClusterer */
public PoissonClusterer() {
}
public static Graph findClusters(Graph incoming, Expression base, Expression target, double meanRate, int distance){
Collection nodes = incoming.getNodes();
Iterator nodeIt = nodes.iterator();
Vector clusterNodes = new Vector();
Vector clusterEdges = new Vector();
System.out.println("x, y, actual, expected, probability");
while (nodeIt.hasNext()){
DelaunayNode next = (DelaunayNode) nodeIt.next();
SimpleFeature nextFeature = next.getFeature();
Object baseObj = base.getValue(nextFeature);
if (!(baseObj instanceof Number)){
throw new RuntimeException("Expression " + base + " must evaluate to a number on feature " + nextFeature);
}
Object targetObj = target.getValue(nextFeature);
if (!(targetObj instanceof Number)){
throw new RuntimeException("Expression " + target + " must evaluate to a number on feature " + nextFeature);
}
double totalBase = ((Number) baseObj).doubleValue();
double totalTarget = ((Number) targetObj).doubleValue();
Collection newEdges = new Vector();
Vector newNodes = new Vector();
newNodes.add(next);
if (distance == 1){
newEdges = next.getEdges();
// System.out.println("this node has " + newEdges.size() + " edges");
Iterator edgeIt = newEdges.iterator();
Vector removals = new Vector();
while (edgeIt.hasNext()){
DelaunayEdge nextEdge = (DelaunayEdge) edgeIt.next();
if (nextEdge.getEuclideanDistance() > 30){
removals.add(nextEdge);
} else {
DelaunayNode neighbor = (DelaunayNode) nextEdge.getOtherNode(next);
if (neighbor == null){
throw new RuntimeException("We have a problem. " + next + " and " + neighbor + " should be neighbors via " + nextEdge + ", but aren't.");
}
SimpleFeature neighborFeature = neighbor.getFeature();
newNodes.add(neighbor);
Object neighborsBaseObj = base.getValue(nextFeature);
if (!(baseObj instanceof Number)){
throw new RuntimeException("Expression " + base + " must evaluate to a number on feature " + neighborFeature);
}
Object neighborsTargetObj = target.getValue(nextFeature);
if (!(targetObj instanceof Number)){
throw new RuntimeException("Expression " + target + " must evaluate to a number on feature " + neighborFeature);
}
totalBase = totalBase + ((Number) baseObj).doubleValue();
totalTarget = totalTarget + ((Number) targetObj).doubleValue();
}
}
newEdges.removeAll(removals);
} else {
for (int i = 0; i <= distance; i++){
Iterator nodeIt2 = newNodes.iterator();
Vector nodesToAdd = new Vector();
Vector edgesToAdd = new Vector();
while (nodeIt2.hasNext()){
DelaunayNode next2 = (DelaunayNode) nodeIt2.next();
// System.out.println("expanding from " + next2);
Collection edges = next2.getEdges();
// System.out.println("its edges are " + edges);
newEdges.addAll(edges);
Iterator another = edges.iterator();
while (another.hasNext()){
DelaunayEdge nextEdge = (DelaunayEdge) another.next();
DelaunayNode farNode = (DelaunayNode) nextEdge.getOtherNode(next2);
// System.out.println("checking " + farNode + " in " + newNodes);
if (!(newNodes.contains(farNode))){
nodesToAdd.add(farNode);
edgesToAdd.add(nextEdge);
// System.out.println("adding node " + farNode + " and edge " + nextEdge);
}
}
}
newNodes.addAll(nodesToAdd);
newEdges.addAll(edgesToAdd);
}
// System.out.println("I've got " + newNodes + " and ");
// System.out.println(newEdges);
totalBase = totalTarget = 0;
Iterator newNodeIt = newNodes.iterator();
while (newNodeIt.hasNext()){
DelaunayNode nextNode = (DelaunayNode) newNodeIt.next();
SimpleFeature nextFeature2 = nextNode.getFeature();
Object neighborsBaseObj = base.getValue(nextFeature2);
if (!(baseObj instanceof Number)){
throw new RuntimeException("Expression " + base + " must evaluate to a number on feature " + nextFeature2);
}
Object neighborsTargetObj = target.getValue(nextFeature2);
if (!(targetObj instanceof Number)){
throw new RuntimeException("Expression " + target + " must evaluate to a number on feature " + nextFeature2);
}
totalBase = totalBase + ((Number) baseObj).doubleValue();
totalTarget = totalTarget + ((Number) targetObj).doubleValue();
}
}
double expectedTarget = meanRate * totalBase;
double top = ((Math.pow(Math.E,(0 - expectedTarget)) * (Math.pow(expectedTarget, totalTarget))));
double bottom = fact((int) Math.round(totalTarget));
double poissonProb = top/bottom;
// System.out.println("testing " + newNodes);
// System.out.println("testing " + newEdges);
System.out.println(next.getCoordinate().x + ", " + next.getCoordinate().y + ", " + totalTarget + ", " + expectedTarget + ", " + poissonProb);
if (poissonProb < threshold){
clusterNodes.addAll(newNodes);
clusterEdges.addAll(newEdges);
}
} //end while (nodeIt.hasNext())
return new BasicGraph(clusterNodes, clusterEdges);
}
private static double iterFact(int i, int f){
if ((i == 0) || (i == 1)){
return f;
} else {
return iterFact(i-1, i*f);
}
}
public static double fact(int i){
return iterFact(i, 1);
}
}