package edu.ucsb.jpregel.system;
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.Math.sqrt;
import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
/**
*
* The value associated with each vertex, v, is:
* 1. the minimum distance to vertex v
* 2. the vertexId of vertex u, where edge (u, v) is on a shortest path to v.
* Since these 2 items constitute a Message, vertexValue is a Message.
*
* @author Pete Cappello
*/
public final class VertexShortestPathEuclidean extends VertexImpl<Point2D.Float, Message<Point2D.Float, Float>, Point2D.Float, Float>
{
public static Combiner combiner = new CombinerMinFloat(); //TODO this field hides another
public VertexShortestPathEuclidean( Point2D.Float vertexId, Map<Point2D.Float, Point2D.Float> edgeMap )
{
super( vertexId, edgeMap );
setVertexValue( new Message( vertexId, Float.MAX_VALUE ) );
}
public VertexShortestPathEuclidean() {} // needed to make vertexFactory
@Override
public VertexImpl make( String line )
{
StringTokenizer stringTokenizer = new StringTokenizer( line );
if ( ! stringTokenizer.hasMoreTokens() )
{
err.println( "EuclideanShortestPathVertex.make: Empty lines are not allowed: line: '" + line + "'");
exit( 1 );
}
float vx = Float.parseFloat( stringTokenizer.nextToken() );
float vy = Float.parseFloat( stringTokenizer.nextToken() );
Point2D.Float vertexId = new Point2D.Float( vx, vy);
Map<Point2D.Float, Point2D.Float> edgeMap = new HashMap<Point2D.Float, Point2D.Float>();
while( stringTokenizer.hasMoreTokens() )
{
float x = Float.parseFloat( stringTokenizer.nextToken() );
float y = Float.parseFloat( stringTokenizer.nextToken() );
Point2D.Float target = new Point2D.Float( x, y );
// TODO VertexShortestPathEuclidean extends UnweightedEdgeVertex which extends VertexImpl
edgeMap.put( target, target );
}
// initialize vertexValue
Float minDistance = ( vx == 0.0 && vy == 0.0 ) ? (float) 0.0 : Float.MAX_VALUE;
Message<Point2D.Float, Float> minDistanceMessage = new Message<Point2D.Float, Float>( new Point2D.Float(), minDistance );
setVertexValue( minDistanceMessage );
return new VertexShortestPathEuclidean( vertexId, edgeMap );
}
@Override
public void compute()
{
// compute currently known minimum distance from source to me
Float minDistance = isSource() ? (float) 0.0 : Float.MAX_VALUE;
Message<Point2D.Float, Float> minDistanceMessage = new Message<Point2D.Float, Float>( getVertexId(), minDistance );
for ( Message<Point2D.Float, Float> message : getMessageQ() )
{
if ( message.getMessageValue() < minDistanceMessage.getMessageValue() )
{
minDistanceMessage = message;
}
}
if ( minDistanceMessage.getMessageValue() < getVertexValue().getMessageValue() )
{
// found a new shorter path from the source to me
setVertexValue( minDistanceMessage ); // update my value: the shortest path to me
// To each target vertex: The shortest known path to you through me just got shorter
for ( Point2D.Float targetVertexId : getEdgeMap().keySet() )
{
float edgeValue = distance( targetVertexId );
Message<Point2D.Float, Float> message = new Message<Point2D.Float, Float>( getVertexId(), minDistanceMessage.getMessageValue() + edgeValue );
sendMessage( targetVertexId, message );
}
// aggregate number of messages sent in this step & in this problem
// aggregateOutputProblemAggregator( new IntegerSumAggregator( getOutEdgeMapSize() ));
// aggregateOutputStepAggregator( new IntegerSumAggregator( getOutEdgeMapSize() ));
}
/* This vote will be overturned, if during this step, a vertex for whom
* I am a target vertex discovered a shorter path to itself,
* in which case, it will send me a message.
*/
// voteToHalt();
}
@Override
public String output()
{
StringBuilder string = new StringBuilder();
string.append( getVertexId() );
string.append( " : ");
string.append( getVertexValue().getVertexId() );
string.append( " - ");
string.append( getVertexValue().getMessageValue() );
return new String( string );
}
/*
* Would prefer to map square subgrids to a part.
*/
@Override
public int getPartId( Point2D.Float vertexId, int numParts )
{
int row = (int) vertexId.getX();
return row % numParts;
}
@Override
public boolean isInitiallyActive() { return isSource(); }
public boolean isSource()
{
Point2D.Float vertex = (Point2D.Float) getVertexId();
return vertex.getX() == 0.0 && vertex.getY() == 0.0;
}
private float distance( Point2D.Float targetVertexId )
{
double x1 = getVertexId().getX();
double y1 = getVertexId().getY();
double x2 = targetVertexId.getX();
double y2 = targetVertexId.getY();
double deltaX = x1 - x2;
double deltaY = y1 - y2;
return (float) sqrt( deltaX * deltaX + deltaY * deltaY );
}
}