performance patches

This commit is contained in:
Arndt 2014-12-28 08:03:27 +01:00
parent 176beba6f6
commit 46db0104e5
13 changed files with 469 additions and 280 deletions

View file

@ -1,172 +0,0 @@
/**
* Implementation for the open-set
* that should be somewhat faster
* and memory-efficient than the original
* version based on java.util.TreeSet
*
* It relies on the two double-linked
* lists implemented in OsmPath
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
public class OpenSet
{
private OsmPath start = new OsmPath();
private OsmPath index2 = new OsmPath();
private int addCount = 0;
private int size = 0;
public void clear()
{
start.nextInSet = null;
start.nextInIndexSet = null;
index2.nextInIndexSet = null;
size = 0;
addCount = 0;
}
public void add( OsmPath path )
{
int ac = path.adjustedCost;
OsmPath p1 = index2;
// fast forward along index2
while( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
if ( p1 == index2 )
{
p1 = start;
}
// search using index1
for(;;)
{
if ( p1.nextInIndexSet != null && p1.nextInIndexSet.adjustedCost < ac )
{
p1 = p1.nextInIndexSet;
}
else if ( p1.nextInSet != null && p1.nextInSet.adjustedCost < ac )
{
p1 = p1.nextInSet;
}
else
{
break;
}
}
OsmPath p2 = p1.nextInSet;
p1.nextInSet = path;
path.prevInSet = p1;
path.nextInSet = p2;
if ( p2 != null ) { p2.prevInSet = path; }
size++;
addCount++;
// feed random samples to the indices
if ( (addCount & 31) == 0 )
{
addIndex( path, start );
}
else if ( (addCount & 1023) == 1023 )
{
addIndex( path, index2 );
}
}
public void remove( OsmPath path )
{
OsmPath p1 = path.prevInSet;
OsmPath p2 = path.nextInSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInSet = null;
path.nextInSet = null;
if ( p2 != null )
{
p2.prevInSet = p1;
}
p1.nextInSet = p2;
removeIndex( path );
size--;
}
public OsmPath first()
{
return start.nextInSet;
}
public int size()
{
return size;
}
public int[] getExtract()
{
int div = size / 1000 + 1;
int[] res = new int[size/div * 2];
int i = 0;
int cnt = 0;
for( OsmPath p = start.nextInSet; p != null; p = p.nextInSet )
{
if ( (++cnt) % div == 0 )
{
OsmNode n = p.getLink().targetNode;
res[i++] = n.ilon;
res[i++] = n.ilat;
}
}
return res;
}
// index operations
private void addIndex( OsmPath path, OsmPath index )
{
int ac = path.adjustedCost;
OsmPath p1 = index;
OsmPath p2 = p1.nextInIndexSet;
while( p2 != null && p2.adjustedCost < ac )
{
p1 = p2;
p2 = p2.nextInIndexSet;
}
p1.nextInIndexSet = path;
path.prevInIndexSet = p1;
path.nextInIndexSet = p2;
if ( p2 != null ) { p2.prevInIndexSet = path; }
}
private void removeIndex( OsmPath path )
{
OsmPath p1 = path.prevInIndexSet;
OsmPath p2 = path.nextInIndexSet;
if ( p1 == null )
{
return; // not in set
}
path.prevInIndexSet = null;
path.nextInIndexSet = null;
if ( p2 != null )
{
p2.prevInIndexSet = p1;
}
p1.nextInIndexSet = p2;
}
}

View file

@ -9,12 +9,6 @@ import btools.mapaccess.*;
final class OsmPath implements OsmLinkHolder final class OsmPath implements OsmLinkHolder
{ {
// double-linked lists for the openSet
public OsmPath nextInSet;
public OsmPath prevInSet;
public OsmPath nextInIndexSet;
public OsmPath prevInIndexSet;
/** /**
* The cost of that path (a modified distance) * The cost of that path (a modified distance)
*/ */
@ -30,12 +24,7 @@ final class OsmPath implements OsmLinkHolder
// if the corresponding node has not // if the corresponding node has not
public short selev; public short selev;
public int adjustedCost = 0; public int airdistance = 0; // distance to endpos
public void setAirDistanceCostAdjustment( int costAdjustment )
{
adjustedCost = cost + costAdjustment;
}
private OsmNode sourcenode; private OsmNode sourcenode;
private OsmLink link; private OsmLink link;

View file

@ -18,6 +18,7 @@ import java.io.FileOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import btools.mapaccess.OsmPos; import btools.mapaccess.OsmPos;
import btools.util.CompactLongMap; import btools.util.CompactLongMap;
@ -219,7 +220,7 @@ public final class OsmTrack
sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" ); sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" );
sb.append( " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" ); sb.append( " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" );
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" ); sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
sb.append( " creator=\"BRouter-1.0.4\" version=\"1.1\">\n" ); sb.append( " creator=\"BRouter-1.1\" version=\"1.1\">\n" );
sb.append( " <trk>\n" ); sb.append( " <trk>\n" );
sb.append(" <name>").append(name).append("</name>\n"); sb.append(" <name>").append(name).append("</name>\n");
sb.append( " <trkseg>\n" ); sb.append( " <trkseg>\n" );
@ -286,6 +287,8 @@ public final class OsmTrack
return sb.toString(); return sb.toString();
} }
public List<String> iternity;
public String formatAsGeoJson() public String formatAsGeoJson()
{ {
StringBuilder sb = new StringBuilder(8192); StringBuilder sb = new StringBuilder(8192);
@ -296,13 +299,24 @@ public final class OsmTrack
sb.append( " {\n" ); sb.append( " {\n" );
sb.append( " \"type\": \"Feature\",\n" ); sb.append( " \"type\": \"Feature\",\n" );
sb.append( " \"properties\": {\n" ); sb.append( " \"properties\": {\n" );
sb.append( " \"creator\": \"BRouter-1.0.4\",\n" ); sb.append( " \"creator\": \"BRouter-1.1\",\n" );
sb.append( " \"name\": \"" ).append( name ).append( "\",\n" ); sb.append( " \"name\": \"" ).append( name ).append( "\",\n" );
sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" ); sb.append( " \"track-length\": \"" ).append( distance ).append( "\",\n" );
sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" ); sb.append( " \"filtered ascend\": \"" ).append( ascend ).append( "\",\n" );
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" ); sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\"\n" ); sb.append( " \"cost\": \"" ).append( cost ).append( "\"\n" );
sb.append( " },\n" ); sb.append( " },\n" );
if ( iternity != null )
{
sb.append( " \"iternity\": [\n" );
for( String s : iternity )
{
sb.append( " \"").append( s ).append( "\",\n" );
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
sb.append( " ],\n" );
}
sb.append( " \"geometry\": {\n" ); sb.append( " \"geometry\": {\n" );
sb.append( " \"type\": \"LineString\",\n" ); sb.append( " \"type\": \"LineString\",\n" );
sb.append( " \"coordinates\": [\n" ); sb.append( " \"coordinates\": [\n" );

View file

@ -40,6 +40,8 @@ public final class RoutingContext implements DistanceChecker
public BExpressionContext expctxWay; public BExpressionContext expctxWay;
public BExpressionContext expctxNode; public BExpressionContext expctxNode;
public boolean serversizing = false;
public int downhillcostdiv; public int downhillcostdiv;
public int downhillcutoff; public int downhillcutoff;
public int uphillcostdiv; public int uphillcostdiv;
@ -52,6 +54,12 @@ public final class RoutingContext implements DistanceChecker
public int elevationmaxbuffer; public int elevationmaxbuffer;
public int elevationbufferreduce; public int elevationbufferreduce;
public double cost1speed;
public double additionalcostfactor;
public double changetime;
public double buffertime;
public double waittimeadjustment;
public void readGlobalConfig( BExpressionContext expctxGlobal ) public void readGlobalConfig( BExpressionContext expctxGlobal )
{ {
downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost", 0.f ); downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost", 0.f );
@ -67,6 +75,12 @@ public final class RoutingContext implements DistanceChecker
elevationpenaltybuffer = (int)(expctxGlobal.getVariableValue( "elevationpenaltybuffer", 5.f )*1000000); elevationpenaltybuffer = (int)(expctxGlobal.getVariableValue( "elevationpenaltybuffer", 5.f )*1000000);
elevationmaxbuffer = (int)(expctxGlobal.getVariableValue( "elevationmaxbuffer", 10.f )*1000000); elevationmaxbuffer = (int)(expctxGlobal.getVariableValue( "elevationmaxbuffer", 10.f )*1000000);
elevationbufferreduce = (int)(expctxGlobal.getVariableValue( "elevationbufferreduce", 0.f )*10000); elevationbufferreduce = (int)(expctxGlobal.getVariableValue( "elevationbufferreduce", 0.f )*10000);
cost1speed = expctxGlobal.getVariableValue( "cost1speed", 22.f );
additionalcostfactor = expctxGlobal.getVariableValue( "additionalcostfactor", 1.5f );
changetime = expctxGlobal.getVariableValue( "changetime", 180.f );
buffertime = expctxGlobal.getVariableValue( "buffertime", 120.f );
waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f );
} }
public RoutingMessageHandler messageHandler = new RoutingMessageHandler(); public RoutingMessageHandler messageHandler = new RoutingMessageHandler();

View file

@ -15,32 +15,33 @@ import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder; import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmNodesMap; import btools.mapaccess.OsmNodesMap;
import btools.util.SortedHeap;
public class RoutingEngine extends Thread public class RoutingEngine extends Thread
{ {
private OsmNodesMap nodesMap; private OsmNodesMap nodesMap;
private NodesCache nodesCache; private NodesCache nodesCache;
private OpenSet openSet = new OpenSet(); private SortedHeap<OsmPath> openSet = new SortedHeap<OsmPath>();
private boolean finished = false; private boolean finished = false;
private List<OsmNodeNamed> waypoints = null; protected List<OsmNodeNamed> waypoints = null;
private int linksProcessed = 0; private int linksProcessed = 0;
private OsmTrack foundTrack = new OsmTrack(); protected OsmTrack foundTrack = new OsmTrack();
private OsmTrack foundRawTrack = null; private OsmTrack foundRawTrack = null;
private int alternativeIndex = 0; private int alternativeIndex = 0;
private String errorMessage = null; protected String errorMessage = null;
private volatile boolean terminated; private volatile boolean terminated;
private File profileDir; protected File profileDir;
private String segmentDir; protected String segmentDir;
private String outfileBase; private String outfileBase;
private String logfileBase; private String logfileBase;
private boolean infoLogEnabled; private boolean infoLogEnabled;
private Writer infoLogWriter; private Writer infoLogWriter;
private RoutingContext routingContext; protected RoutingContext routingContext;
private double airDistanceCostFactor; private double airDistanceCostFactor;
private OsmTrack guideTrack; private OsmTrack guideTrack;
@ -80,8 +81,8 @@ public class RoutingEngine extends Thread
BExpressionMetaData meta = new BExpressionMetaData(); BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContext expctxGlobal = new BExpressionContext( "global", meta ); BExpressionContext expctxGlobal = new BExpressionContext( "global", meta );
rc.expctxWay = new BExpressionContext( "way", meta ); rc.expctxWay = new BExpressionContext( "way", rc.serversizing ? 262144 : 4096, meta );
rc.expctxNode = new BExpressionContext( "node", 1024, meta ); rc.expctxNode = new BExpressionContext( "node", rc.serversizing ? 16384 : 1024, meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) ); meta.readMetaData( new File( profileDir, "lookups.dat" ) );
@ -504,7 +505,6 @@ public class RoutingEngine extends Thread
if ( pe.cost >= costdelta ) if ( pe.cost >= costdelta )
{ {
pe.cost -= costdelta; pe.cost -= costdelta;
pe.adjustedCost -= costdelta;
if ( guideTrack != null ) if ( guideTrack != null )
{ {
@ -559,7 +559,7 @@ public class RoutingEngine extends Thread
wp.radius = 1e9; wp.radius = 1e9;
OsmPath testPath = new OsmPath( null, startPath, link, null, guideTrack != null, routingContext ); OsmPath testPath = new OsmPath( null, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( (int)( nextNode.calcDistance( endPos ) * airDistanceCostFactor ) ); testPath.airdistance = nextNode.calcDistance( endPos );
if ( wp.radius < minradius ) if ( wp.radius < minradius )
{ {
bestPath = testPath; bestPath = testPath;
@ -593,10 +593,7 @@ public class RoutingEngine extends Thread
if ( wp != null ) wp.radius = 1e-5; if ( wp != null ) wp.radius = 1e-5;
OsmPath testPath = new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext ); return new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext );
testPath.setAirDistanceCostAdjustment( 0 );
return testPath;
} }
finally finally
{ {
@ -636,8 +633,6 @@ public class RoutingEngine extends Thread
OsmPath startPath1 = getStartPath( start1, start2, startWp, endWp, sameSegmentSearch ); OsmPath startPath1 = getStartPath( start1, start2, startWp, endWp, sameSegmentSearch );
OsmPath startPath2 = getStartPath( start2, start1, startWp, endWp, sameSegmentSearch ); OsmPath startPath2 = getStartPath( start2, start1, startWp, endWp, sameSegmentSearch );
int maxAdjCostFromQueue = 0;
// check for an INITIAL match with the cost-cutting-track // check for an INITIAL match with the cost-cutting-track
if ( costCuttingTrack != null ) if ( costCuttingTrack != null )
{ {
@ -655,8 +650,8 @@ public class RoutingEngine extends Thread
synchronized( openSet ) synchronized( openSet )
{ {
openSet.clear(); openSet.clear();
if ( startPath1.cost >= 0 ) openSet.add( startPath1 ); addToOpenset( startPath1 );
if ( startPath2.cost >= 0 ) openSet.add( startPath2 ); addToOpenset( startPath2 );
} }
while(!terminated) while(!terminated)
{ {
@ -671,16 +666,10 @@ public class RoutingEngine extends Thread
OsmPath path = null; OsmPath path = null;
synchronized( openSet ) synchronized( openSet )
{ {
if ( openSet.size() == 0 ) break; path = openSet.popLowestKeyValue();
path = openSet.first();
openSet.remove( path );
} }
if ( path == null ) break;
if ( path.adjustedCost < maxAdjCostFromQueue && airDistanceCostFactor == 0.) if ( path.airdistance == -1 ) continue;
{
throw new RuntimeException( "assertion failed: path.adjustedCost < maxAdjCostFromQueue: " + path.adjustedCost + "<" + maxAdjCostFromQueue );
}
maxAdjCostFromQueue = path.adjustedCost;
if ( matchPath != null && fastPartialRecalc && firstMatchCost < 500 && path.cost > 30L*firstMatchCost ) if ( matchPath != null && fastPartialRecalc && firstMatchCost < 500 && path.cost > 30L*firstMatchCost )
{ {
@ -740,8 +729,7 @@ public class RoutingEngine extends Thread
} }
// recheck cutoff before doing expensive stuff // recheck cutoff before doing expensive stuff
int airDistance2 = currentNode.calcDistance( endPos ); if ( path.cost + path.airdistance > maxTotalCost + 10 )
if ( path.cost + airDistance2 > maxTotalCost + 10 )
{ {
continue; continue;
} }
@ -824,18 +812,14 @@ public class RoutingEngine extends Thread
} }
if ( otherPath != path ) if ( otherPath != path )
{ {
synchronized( openSet ) otherPath.airdistance = -1; // invalidate the entry in the open set
{
openSet.remove( otherPath );
}
} }
} }
if ( bestPath != null ) if ( bestPath != null )
{ {
int airDistance = isFinalLink ? 0 : nextNode.calcDistance( endPos ); bestPath.airdistance = isFinalLink ? 0 : nextNode.calcDistance( endPos );
bestPath.setAirDistanceCostAdjustment( (int)( airDistance * airDistanceCostFactor ) );
if ( isFinalLink || bestPath.cost + airDistance <= maxTotalCost + 10 ) if ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 10 )
{ {
// add only if this may beat an existing path for that link // add only if this may beat an existing path for that link
OsmLinkHolder dominator = link.firstlinkholder; OsmLinkHolder dominator = link.firstlinkholder;
@ -854,7 +838,7 @@ public class RoutingEngine extends Thread
link.addLinkHolder( bestPath ); link.addLinkHolder( bestPath );
synchronized( openSet ) synchronized( openSet )
{ {
openSet.add( bestPath ); addToOpenset( bestPath );
} }
} }
} }
@ -870,6 +854,14 @@ public class RoutingEngine extends Thread
return null; return null;
} }
private void addToOpenset( OsmPath path )
{
if ( path.cost >= 0 )
{
openSet.add( path.cost + (int)(path.airdistance*airDistanceCostFactor), path );
}
}
private void preloadPosition( OsmNode n, int minRingWidth, int minCount ) private void preloadPosition( OsmNode n, int minRingWidth, int minCount )
{ {
int c = 0; int c = 0;
@ -991,7 +983,16 @@ public class RoutingEngine extends Thread
{ {
synchronized( openSet ) synchronized( openSet )
{ {
return openSet.getExtract(); List<OsmPath> extract = openSet.getExtract();
int[] res = new int[extract.size() * 2];
int i = 0;
for( OsmPath p : extract )
{
OsmNode n = p.getLink().targetNode;
res[i++] = n.ilon;
res[i++] = n.ilat;
}
return res;
} }
} }
@ -1044,4 +1045,10 @@ public class RoutingEngine extends Thread
{ {
terminated = true; terminated = true;
} }
public boolean isTerminated()
{
return terminated;
}
} }

View file

@ -50,8 +50,12 @@ public final class BExpressionContext
// hash-cache for function results // hash-cache for function results
private byte[][] _arrayBitmap; private byte[][] _arrayBitmap;
private boolean[] _arrayInverse;
private int[] _arrayCrc;
private int currentHashBucket = -1; private int currentHashBucket = -1;
private byte[] currentByteArray = null; private byte[] currentByteArray = null;
private boolean currentInverseDirection= false;
public List<BExpression> expressionList; public List<BExpression> expressionList;
@ -104,7 +108,9 @@ public final class BExpressionContext
if ( Boolean.getBoolean( "disableExpressionCache" ) ) hashSize = 1; if ( Boolean.getBoolean( "disableExpressionCache" ) ) hashSize = 1;
_arrayBitmap = new byte[hashSize][]; _arrayBitmap = new byte[hashSize][];
_arrayInverse = new boolean[hashSize];
_arrayCrc = new int[hashSize];
_arrayCostfactor = new float[hashSize]; _arrayCostfactor = new float[hashSize];
_arrayTurncost = new float[hashSize]; _arrayTurncost = new float[hashSize];
@ -163,7 +169,7 @@ public final class BExpressionContext
// crosscheck: decode and compare // crosscheck: decode and compare
int[] ld2 = new int[lookupValues.size()]; int[] ld2 = new int[lookupValues.size()];
decode( ld2, ab ); decode( ld2, false, ab );
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{ {
if ( ld2[inum] != ld[inum] ) throw new RuntimeException( "assertion failed encoding " + getKeyValueDescription(false, ab) ); if ( ld2[inum] != ld[inum] ) throw new RuntimeException( "assertion failed encoding " + getKeyValueDescription(false, ab) );
@ -208,21 +214,21 @@ public final class BExpressionContext
*/ */
public void decode( byte[] ab ) public void decode( byte[] ab )
{ {
decode( lookupData, ab ); decode( lookupData, false, ab );
lookupDataValid = true; lookupDataValid = true;
} }
/** /**
* decode a byte-array into a lookup data array * decode a byte-array into a lookup data array
*/ */
public void decode( int[] ld, byte[] ab ) private void decode( int[] ld, boolean inverseDirection, byte[] ab )
{ {
if ( !meta.readVarLength ) { decodeFix( ld, ab ); return; } if ( !meta.readVarLength ) { decodeFix( ld, ab ); return; }
BitCoderContext ctx = new BitCoderContext(ab); BitCoderContext ctx = new BitCoderContext(ab);
// start with first bit hardwired ("reversedirection") // start with first bit hardwired ("reversedirection")
ld[0] = ctx.decodeBit() ? 2 : 0; ld[0] = inverseDirection ^ ctx.decodeBit() ? 2 : 0;
// all others are generic // all others are generic
int inum = 1; int inum = 1;
@ -276,13 +282,10 @@ public final class BExpressionContext
public String getKeyValueDescription( boolean inverseDirection, byte[] ab ) public String getKeyValueDescription( boolean inverseDirection, byte[] ab )
{ {
int inverseBitByteIndex = meta.readVarLength ? 0 : 7; int inverseBitByteIndex = meta.readVarLength ? 0 : 7;
int abLen = ab.length; // int abLen = ab.length;
byte[] ab_copy = new byte[abLen];
System.arraycopy( ab, 0, ab_copy, 0 , abLen );
if ( inverseDirection ) ab_copy[inverseBitByteIndex] ^= 1;
StringBuilder sb = new StringBuilder( 200 ); StringBuilder sb = new StringBuilder( 200 );
decode( lookupData, ab_copy ); decode( lookupData, inverseDirection, ab );
for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names for( int inum = 0; inum < lookupValues.size(); inum++ ) // loop over lookup names
{ {
BExpressionLookupValue[] va = lookupValues.get(inum); BExpressionLookupValue[] va = lookupValues.get(inum);
@ -344,7 +347,9 @@ public final class BExpressionContext
} }
} }
public long requests;
public long requests2;
public long cachemisses;
/** /**
* evaluates the data in the given byte array * evaluates the data in the given byte array
@ -353,55 +358,53 @@ public final class BExpressionContext
*/ */
public boolean evaluate( boolean inverseDirection, byte[] ab, BExpressionReceiver receiver ) public boolean evaluate( boolean inverseDirection, byte[] ab, BExpressionReceiver receiver )
{ {
requests ++;
lookupDataValid = false; // this is an assertion for a nasty pifall lookupDataValid = false; // this is an assertion for a nasty pifall
int inverseBitByteIndex = meta.readVarLength ? 0 : 7; int inverseBitByteIndex = meta.readVarLength ? 0 : 7;
int abLen = ab.length; // calc hash bucket from crc
boolean equalsCurrent = currentHashBucket >= 0 && abLen == currentByteArray.length; int lastHashBucket = currentHashBucket;
if ( equalsCurrent ) int crc = Crc32.crcWithInverseBit(ab, inverseDirection ? inverseBitByteIndex : -1 );
{ int hashSize = _arrayBitmap.length;
for( int i=0; i<abLen; i++ ) currentHashBucket = (crc & 0xfffffff) % hashSize;
{ currentByteArray = ab;
byte b = ab[i]; currentInverseDirection = inverseDirection;
if ( i == inverseBitByteIndex && inverseDirection ) b ^= 1;
if ( b != currentByteArray[i] ) { equalsCurrent = false; break; }
}
}
if ( equalsCurrent )
{
return true;
}
else
{
// calc hash bucket from crc
int crc = Crc32.crc( abBuf, 0, abLen );
int hashSize = _arrayBitmap.length;
currentHashBucket = (crc & 0xfffffff) % hashSize;
currentByteArray = new byte[abLen];
System.arraycopy( ab, 0, currentByteArray, 0 , abLen );
if ( inverseDirection ) currentByteArray[inverseBitByteIndex] ^= 1;
}
boolean hashBucketEquals = false;
byte[] abBucket = _arrayBitmap[currentHashBucket]; byte[] abBucket = _arrayBitmap[currentHashBucket];
if ( abBucket != null && abBucket.length == abLen ) boolean inverseBucket = _arrayInverse[currentHashBucket];
if ( ab == abBucket && inverseBucket == inverseDirection ) // fast identity check
{ {
return lastHashBucket == currentHashBucket;
}
requests2++;
// compare input value to hash bucket content
boolean hashBucketEquals = false;
if ( crc == _arrayCrc[currentHashBucket] )
{
int abLen = ab.length;
if ( abBucket != null && abBucket.length == ab.length )
{
hashBucketEquals = true; hashBucketEquals = true;
boolean isInverse = inverseDirection ^ inverseBucket;
for( int i=0; i<abLen; i++ ) for( int i=0; i<abLen; i++ )
{ {
if ( abBucket[i] != currentByteArray[i] ) { hashBucketEquals = false; break; } byte b = ab[i];
if ( isInverse && i == inverseBitByteIndex ) b ^= 1;
if ( abBucket[i] != b ) { hashBucketEquals = false; break; }
} }
}
} }
if ( hashBucketEquals ) return false; if ( hashBucketEquals ) return lastHashBucket == currentHashBucket;
cachemisses++;
_arrayBitmap[currentHashBucket] = currentByteArray; _arrayBitmap[currentHashBucket] = currentByteArray;
_arrayInverse[currentHashBucket] = currentInverseDirection;
_arrayCrc[currentHashBucket] = crc;
_receiver = receiver; _receiver = receiver;
decode( lookupData, currentByteArray ); decode( lookupData, currentInverseDirection, currentByteArray );
evaluate( lookupData ); evaluate( lookupData );
_arrayCostfactor[currentHashBucket] = variableData[costfactorIdx]; _arrayCostfactor[currentHashBucket] = variableData[costfactorIdx];

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="4" android:versionCode="5"
android:versionName="1.0.2" package="btools.routingapp"> android:versionName="1.1" package="btools.routingapp">
<application android:icon="@drawable/icon" android:label="@string/app_name"> <application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BRouterActivity" <activity android:name=".BRouterActivity"
android:label="@string/app_name" android:label="@string/app_name"

View file

@ -536,7 +536,7 @@ private long startTime = 0L;
} }
else else
{ {
String result = "version = BRouter-1.0.4\n" String result = "version = BRouter-1.1\n"
+ "distance = " + cr.getDistance()/1000. + " km\n" + "distance = " + cr.getDistance()/1000. + " km\n"
+ "filtered ascend = " + cr.getAscend() + " m\n" + "filtered ascend = " + cr.getAscend() + " m\n"
+ "plain ascend = " + cr.getPlainAscend(); + "plain ascend = " + cr.getPlainAscend();

View file

@ -2,19 +2,16 @@ package btools.server;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.InetAddress;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.TreeMap;
import btools.router.OsmNodeNamed; import btools.router.OsmNodeNamed;
import btools.router.OsmTrack; import btools.router.OsmTrack;
@ -129,7 +126,7 @@ public class RouteServer extends Thread
public static void main(String[] args) throws Exception public static void main(String[] args) throws Exception
{ {
System.out.println("BRouter 1.0.4 / 28092014"); System.out.println("BRouter 1.1 / 27122014");
if ( args.length != 5 ) if ( args.length != 5 )
{ {
System.out.println("serve BRouter protocol"); System.out.println("serve BRouter protocol");

View file

@ -41,6 +41,7 @@ public class ServerHandler extends RequestHandler {
public RoutingContext readRoutingContext() public RoutingContext readRoutingContext()
{ {
rc = new RoutingContext(); rc = new RoutingContext();
rc.serversizing = true;
String profile = params.get( "profile" ); String profile = params.get( "profile" );
// when custom profile replace prefix with directory path // when custom profile replace prefix with directory path

View file

@ -30,6 +30,19 @@ public class Crc32
return crc; return crc;
} }
public static int crcWithInverseBit( byte[] ab, int inverseBitByteIndex )
{
int crc = 0xFFFFFFFF;
int end = ab.length;
for( int j=0; j<end; j++ )
{
byte b = ab[j];
if ( j == inverseBitByteIndex ) b ^= 1;
crc = (crc >>> 8) ^ crctable[(crc ^ b) & 0xff];
}
return crc;
}
private static int[] crctable = { private static int[] crctable = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,

View file

@ -0,0 +1,258 @@
package btools.util;
import java.util.ArrayList;
import java.util.List;
/**
* Memory efficient Heap to get the lowest-key value
* of a set of key-object pairs
*
* @author ab
*/
public class SortedHeap<V>
{
private int[][] al;
private int[] pa;
private int[] lp; // the low pointers
private Object[][] vla; // value list array
protected static final int MAXLISTS = 31; // enough for size Integer.MAX_VALUE
private int size;
private boolean isClear = false;
public SortedHeap()
{
clear();
}
/**
* @return the lowest key value, or null if none
*/
public V popLowestKeyValue()
{
int minId = 0;
int minIdx = -1;
for ( int i=1;; i++ )
{
int[] ali = al[i];
if ( ali == null ) break;
int lpi = lp[i];
if ( lpi < ali.length )
{
int currentId = ali[lpi];
if ( minIdx < 0 || currentId < minId )
{
minIdx = i;
minId = currentId;
}
}
}
if ( minIdx == -1 ) return null;
int lp_minIdx = lp[minIdx]++;
Object[] vla_minIdx = vla[minIdx];
V res =(V)vla_minIdx[lp_minIdx];
vla_minIdx[lp_minIdx] = null;
size--;
return res;
}
/**
* add a key value pair to the heap
*
* @param id the key to insert
* @param value the value to insert object
*/
public void add( int key, V value )
{
isClear = false;
size++;
// trivial shortcut if first array empty
if ( lp[1] == 1)
{
al[1][0] = key;
vla[1][0] = value;
lp[1] = 0;
return;
}
// trivial shortcut if second array empty
if ( lp[2] > 0 )
{
int[] al2 = al[2];
Object[] vla2 = vla[2];
int key1;
Object val1;
if ( lp[2] == 2 )
{
key1 = al[1][0];
val1 = vla[1][0];
lp[1] = 1;
}
else // == 1
{
key1 = al2[1];
val1 = vla2[1];
}
lp[2] = 0;
if ( key1 < key )
{
al2[0] = key1;
vla2[0] = val1;
al2[1] = key;
vla2[1] = value;
}
else
{
al2[1] = key1;
vla2[1] = val1;
al2[0] = key;
vla2[0] = value;
}
return;
}
// put the new entry in the first array
al[0][0] = key;
vla[0][0] = value;
pa[0] = 1;
pa[1] = 1;
pa[2] = 2;
// determine the first array big enough to take them all
int cnt = 4; // value count up to idx
int idx = 3;
int n = 4;
for(;;)
{
cnt += n-lp[idx];
if ( cnt <= n ) break;
pa[idx++] = n;
n <<= 1;
}
if ( idx == MAXLISTS )
{
throw new IllegalArgumentException( "overflow" );
}
// create it if not existant
if ( al[idx] == null )
{
al[idx] = new int[n];
vla[idx] = new Object[n];
}
int[] al_t = al[idx];
Object[] vla_t = vla[idx];
int lp_t = lp[idx];
// shift down content if any
if ( lp_t < n )
{
System.arraycopy(al_t, lp_t, al_t, 0, n-lp_t);
System.arraycopy(vla_t, lp_t, vla_t, 0, n-lp_t);
}
lp[idx] = 0;
pa[idx] = n - lp_t;
// now merge the contents of arrays 0...idx-1 into idx
while ( cnt > 0 )
{
int maxId = 0;
int maxIdx = -1;
for ( int i=0; i<=idx; i++ )
{
int p = pa[i];
if ( p > lp[i] )
{
int currentId = al[i][p-1];
if ( maxIdx < 0 || currentId > maxId )
{
maxIdx = i;
maxId = currentId;
}
}
}
// current maximum found, copy to target array
--n;
al[idx][n] = maxId;
vla[idx][n] = vla[maxIdx][pa[maxIdx]-1];
--cnt;
--pa[maxIdx];
}
lp[idx] = n;
while(--idx > 0) lp[idx] = al[idx].length;
}
public void clear()
{
if ( !isClear )
{
isClear = true;
size = 0;
// pointer array
pa = new int[MAXLISTS];
lp = new int[MAXLISTS];
// allocate key lists
al = new int[MAXLISTS][];
al[0] = new int[1]; // make the first arrays
al[1] = new int[1];
al[2] = new int[2];
// same for the values
vla = new Object[MAXLISTS][];
vla[0] = new Object[1];
vla[1] = new Object[1];
vla[2] = new Object[2];
int n = 1;
lp[0] = 0;
for( int idx=1; idx < MAXLISTS; idx++ )
{
lp[idx] = n;
n <<= 1;
}
}
}
public List<V> getExtract()
{
int div = size / 1000 + 1;
ArrayList<V> res = new ArrayList<V>(size / div );
int cnt = 0;
for ( int i=1;; i++ )
{
int[] ali = al[i];
if ( ali == null ) break;
int lpi = lp[i];
Object[] vlai = vla[i];
int n = ali.length;
while ( lpi < n )
{
if ( (++cnt) % div == 0 )
{
res.add( (V)vla[i][lpi] );
}
lpi++;
}
}
return res;
}
}

View file

@ -0,0 +1,65 @@
package btools.util;
import java.util.Random;
import java.util.HashMap;
import java.util.HashSet;
import org.junit.Assert;
import org.junit.Test;
public class SortedHeapTest
{
@Test
public void sortedHeapTest1()
{
SortedHeap<String> sh = new SortedHeap<String>();
Random rnd = new Random();
for( int i = 0; i< 100000; i++ )
{
int val = rnd.nextInt( 1000000 );
sh.add( val, "" + val );
val = rnd.nextInt( 1000000 );
sh.add( val, "" + val );
sh.popLowestKeyValue();
}
int cnt = 0;
int lastval = 0;
for(;;)
{
String s = sh.popLowestKeyValue();
if ( s == null ) break;
cnt ++;
int val = Integer.parseInt( s );
Assert.assertTrue( "sorting test", val >= lastval );
lastval = val;
}
Assert.assertTrue( "total count test", cnt == 100000 );
}
@Test
public void sortedHeapTest2()
{
SortedHeap<String> sh = new SortedHeap<String>();
Random rnd = new Random();
for( int i = 0; i< 100000; i++ )
{
sh.add( i, "" + i );
}
int cnt = 0;
int expected = 0;
for(;;)
{
String s = sh.popLowestKeyValue();
if ( s == null ) break;
cnt ++;
int val = Integer.parseInt( s );
Assert.assertTrue( "sequence test", val == expected );
expected++;
}
Assert.assertTrue( "total count test", cnt == 100000 );
}
}