profile syntax: syntactic sugar

This commit is contained in:
Arndt 2015-03-01 13:04:11 +01:00
parent 8676f5e081
commit 6811ea524e
5 changed files with 245 additions and 122 deletions

View file

@ -292,7 +292,7 @@ final class OsmPath implements OsmLinkHolder
+ "\t" + linkturncost
+ "\t" + linknodecost
+ "\t" + linkinitcost
+ rc.expctxWay.getKeyValueDescription( link.counterLinkWritten, description );
+ "\t" + rc.expctxWay.getKeyValueDescription( link.counterLinkWritten, description );
}
if ( stopAtEndpoint )

View file

@ -31,9 +31,18 @@ final class BExpression
// Parse the expression and all subexpression
public static BExpression parse( BExpressionContext ctx, int level ) throws Exception
{
return parse( ctx, level, null );
}
private static BExpression parse( BExpressionContext ctx, int level, String optionalToken ) throws Exception
{
boolean brackets = false;
String operator = ctx.parseToken();
if ( optionalToken != null && optionalToken.equals( operator ) )
{
operator = ctx.parseToken();
}
if ( "(".equals( operator ) )
{
brackets = true;
@ -145,6 +154,16 @@ final class BExpression
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
}
else if ( "true".equals( operator ) )
{
exp.numberValue = 1.f;
exp.typ = NUMBER_EXP;
}
else if ( "false".equals( operator ) )
{
exp.numberValue = 0.f;
exp.typ = NUMBER_EXP;
}
else
{
try
@ -163,17 +182,17 @@ final class BExpression
// parse operands
if ( nops > 0 )
{
exp.op1 = BExpression.parse( ctx, level+1 );
exp.op1 = BExpression.parse( ctx, level+1, exp.typ == ASSIGN_EXP ? "=" : null );
}
if ( nops > 1 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "then" );
exp.op2 = BExpression.parse( ctx, level+1 );
exp.op2 = BExpression.parse( ctx, level+1, null );
}
if ( nops > 2 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "else" );
exp.op3 = BExpression.parse( ctx, level+1 );
exp.op3 = BExpression.parse( ctx, level+1, null );
}
if ( brackets )
{

View file

@ -19,6 +19,7 @@ import java.util.TreeMap;
import btools.util.BitCoderContext;
import btools.util.Crc32;
import java.util.Random;
public final class BExpressionContext
@ -172,7 +173,7 @@ public final class BExpressionContext
decode( ld2, false, ab );
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 inum=" + inum + " val=" + ld[inum] + " " + getKeyValueDescription(false, ab) );
}
return ab;
@ -471,6 +472,51 @@ public final class BExpressionContext
return null;
}
/**
* generate random values for regression testing
*/
public int[] generateRandomValues( Random rnd )
{
int[] data = createNewLookupData();
data[0] = 2*rnd.nextInt( 2 ); // reverse-direction = 0 or 2
for( int inum = 1; inum < data.length; inum++ )
{
int nvalues = lookupValues.get( inum ).length;
data[inum] = 0;
if ( inum > 1 && rnd.nextInt( 10 ) > 0 ) continue; // tags other than highway only 10%
data[inum] = rnd.nextInt( nvalues );
}
lookupDataValid = true;
return data;
}
public void assertAllVariablesEqual( BExpressionContext other )
{
int nv = variableData.length;
int nv2 = other.variableData.length;
if ( nv != nv2 ) throw new RuntimeException( "mismatch in variable-count: " + nv + "<->" + nv2 );
for( int i=0; i<nv; i++ )
{
if ( variableData[i] != other.variableData[i] )
{
throw new RuntimeException( "mismatch in variable " + variableName(i) + " " + variableData[i] + "<->" + other.variableData[i]
+ "\ntags = " + getKeyValueDescription( false, encode() ) );
}
}
}
private String variableName( int idx )
{
for( Map.Entry<String,Integer> e : variableNumbers.entrySet() )
{
if ( e.getValue().intValue() == idx )
{
return e.getKey();
}
}
throw new RuntimeException( "no variable for index" + idx );
}
/**
* add a new lookup-value for the given name to the given lookupData array.
* If no array is given (null value passed), the value is added to

View file

@ -0,0 +1,59 @@
package btools.expressions;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import btools.util.BitCoderContext;
import btools.util.Crc32;
import java.util.Random;
public final class ProfileComparator
{
public static void main( String[] args )
{
if ( args.length != 4 )
{
System.out.println( "usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>" );
return;
}
File lookupFile = new File( args[0] );
File profile1File = new File( args[1] );
File profile2File = new File( args[2] );
int nsamples = Integer.parseInt( args[3] );
testContext( lookupFile, profile1File, profile2File, nsamples, "way" );
testContext( lookupFile, profile1File, profile2File, nsamples, "node" );
}
private static void testContext( File lookupFile, File profile1File, File profile2File, int nsamples, String contextName )
{
// read lookup.dat + profiles
BExpressionMetaData meta1 = new BExpressionMetaData();
BExpressionMetaData meta2 = new BExpressionMetaData();
BExpressionContext expctx1 = new BExpressionContext(contextName, 4096, meta1 );
BExpressionContext expctx2 = new BExpressionContext(contextName, 4096, meta2 );
meta1.readMetaData( lookupFile );
meta2.readMetaData( lookupFile );
expctx1.parseFile( profile1File, "global" );
expctx2.parseFile( profile2File, "global" );
Random rnd = new Random();
for( int i=0; i<nsamples; i++ )
{
int[] data = expctx1.generateRandomValues( rnd );
expctx1.evaluate( data );
expctx2.evaluate( data );
expctx1.assertAllVariablesEqual( expctx2 );
}
}
}

View file

@ -8,21 +8,21 @@
# Use the following switches to change behaviour
# (1=yes, 0=no):
assign consider_elevation 1 # set to 0 to ignore elevation in routing
assign allow_steps 1 # set to 0 to disallow steps
assign allow_ferries 1 # set to 0 to disallow ferries
assign ignore_cycleroutes 0 # set to 1 for better elevation results
assign stick_to_cycleroutes 0 # set to 1 to just follow cycleroutes
assign avoid_unsafe 0 # set to 1 to avoid standard highways
assign consider_elevation = true # set to false to ignore elevation in routing
assign allow_steps = true # set to false to disallow steps
assign allow_ferries = true # set to false to disallow ferries
assign ignore_cycleroutes = false # set to true for better elevation results
assign stick_to_cycleroutes = false # set to true to just follow cycleroutes
assign avoid_unsafe = false # set to true to avoid standard highways
assign validForBikes 1
assign validForBikes = true
# the elevation parameters
assign downhillcost switch consider_elevation 60 0
assign downhillcutoff 1.5
assign uphillcost 0
assign uphillcutoff 1.5
assign downhillcost = if consider_elevation then 60 else 0
assign downhillcutoff = 1.5
assign uphillcost = 0
assign uphillcutoff = 1.5
---context:way # following code refers to way-tags
@ -30,14 +30,25 @@ assign uphillcutoff 1.5
# pre-calculate some logical expressions
#
assign any_cycleroute or route_bicycle_icn=yes or route_bicycle_ncn=yes or route_bicycle_rcn=yes route_bicycle_lcn=yes
assign nodeaccessgranted or any_cycleroute lcn=yes
assign any_cycleroute =
if route_bicycle_icn=yes then true
else if route_bicycle_ncn=yes then true
else if route_bicycle_rcn=yes then true
else if route_bicycle_lcn=yes then true
else false
assign is_ldcr and any_cycleroute not ignore_cycleroutes
assign isbike or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes
assign ispaved or surface=paved or surface=asphalt or surface=concrete surface=paving_stones
assign isunpaved not or surface= or ispaved or surface=fine_gravel surface=cobblestone
assign probablyGood or ispaved and isbike not isunpaved
assign nodeaccessgranted =
if any_cycleroute then true
else lcn=yes
assign is_ldcr =
if ignore_cycleroutes then false
else any_cycleroute
assign isbike = or bicycle=yes or or bicycle=permissive bicycle=designated lcn=yes
assign ispaved = surface=paved|asphalt|concrete|paving_stones
assign isunpaved = not or surface= or ispaved surface=fine_gravel|cobblestone
assign probablyGood = or ispaved and isbike not isunpaved
#
@ -46,59 +57,53 @@ assign probablyGood or ispaved and isbike not isunpaved
# (Suppressing turncost while following longdistance-cycleways
# makes them a little bit more magnetic)
#
assign turncost switch is_ldcr 0 90
assign turncost = if is_ldcr then 0 else 90
#
# calculate the initial cost
# this is added to the total cost each time the costfactor
# changed
#
assign initialcost switch route=ferry 10000 0
assign initialcost = if route=ferry then 10000 else 0
#
# implicit access here just from the motorroad tag
# (implicit access rules from highway tag handled elsewhere)
#
assign defaultaccess
switch access=
not motorroad=yes
switch or access=private access=no
0
1
assign defaultaccess =
if access= then not motorroad=yes
else if access=private|no then false
else true
#
# calculate logical bike access
#
assign bikeaccess
or any_cycleroute
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
not or bicycle=private or bicycle=no bicycle=dismount
assign bikeaccess =
if any_cycleroute then true
else if bicycle= then
(
if vehicle= then defaultaccess
else not vehicle=private|no
)
else not bicycle=private|no|dismount
#
# calculate logical foot access
#
assign footaccess
or bikeaccess
or bicycle=dismount
switch foot=
defaultaccess
not or foot=private foot=no
assign footaccess =
if bikeaccess then true
else if bicycle=dismount then true
else if foot= then defaultaccess
else not foot=private|no
#
# if not bike-, but foot-acess, just a moderate penalty,
# otherwise access is forbidden
#
assign accesspenalty
switch bikeaccess
0
switch footaccess
4
100000
assign accesspenalty =
if bikeaccess then 0
else if footaccess then 4
else 100000
#
# handle one-ways. On primary roads, wrong-oneways should
@ -106,19 +111,21 @@ assign accesspenalty
# 4 to the costfactor (making it at least 5 - you are allowed
# to push your bike)
#
assign oneway
switch oneway=
junction=roundabout
or oneway=yes or oneway=true oneway=1
assign oneway =
if oneway= then junction=roundabout else oneway=yes|true|1
assign onewaypenalty =
if ( if reversedirection=yes then oneway else oneway=-1 ) then
(
if ( cycleway=opposite|opposite_lane|opposite_track ) then 0
else if ( oneway:bicycle=no ) then 0
else if ( highway=primary|primary_link ) then 50
else if ( highway=secondary|secondary_link ) then 30
else if ( highway=tertiary|tertiary_link ) then 20
else 4.0
)
else 0.0
assign onewaypenalty
switch switch reversedirection=yes oneway oneway=-1
switch or cycleway=opposite or cycleway=opposite_lane or cycleway=opposite_track oneway:bicycle=no 0
switch or highway=primary highway=primary_link 50
switch or highway=secondary highway=secondary_link 30
switch or highway=tertiary highway=tertiary_link 20
4.0
0.0
#
# calculate the cost-factor, which is the factor
@ -127,106 +134,98 @@ assign onewaypenalty
# must be >=1 and it's supposed to be close to 1 for
# the type of way the routing profile is searching for
#
assign costfactor
assign costfactor =
add max onewaypenalty accesspenalty
add ( max onewaypenalty accesspenalty )
switch and highway= not route=ferry 100000
if ( and highway= not route=ferry ) then 100000
#
# steps and ferries are special. Note this is handled
# before the cycleroute-switch, to be able
# to really exlude them be setting cost to infinity
#
switch highway=steps switch allow_steps 40 100000
switch route=ferry switch allow_ferries 5.67 100000
else if ( highway=steps ) then ( if allow_steps then 40 else 100000 )
else if ( route=ferry ) then ( if allow_ferries then 5.67 else 100000 )
#
# handle long-distance cycle-routes.
#
switch is_ldcr 1 # always treated as perfect (=1)
add switch stick_to_cycleroutes 0.5 0.05 # everything else somewhat up
else if ( is_ldcr ) then 1 # always treated as perfect (=1)
else
add ( if stick_to_cycleroutes then 0.5 else 0.05 ) # everything else somewhat up
#
# some other highway types
#
switch highway=pedestrian 3
switch highway=bridleway 5
switch highway=cycleway 1
switch or highway=residential highway=living_street switch isunpaved 1.5 1.1
switch highway=service switch isunpaved 1.6 1.3
if ( highway=pedestrian ) then 3
else if ( highway=bridleway ) then 5
else if ( highway=cycleway ) then 1
else if ( highway=residential|living_street ) then ( if isunpaved then 1.5 else 1.1 )
else if ( highway=service ) then ( if isunpaved then 1.6 else 1.3 )
#
# tracks and track-like ways are rated mainly be tracktype/grade
# But note that if no tracktype is given (mainly for road/path/footway)
# it can be o.k. if there's any other hint for quality
#
switch or highway=track or highway=road or highway=path highway=footway
switch tracktype=grade1 switch probablyGood 1.0 1.3
switch tracktype=grade2 switch probablyGood 1.1 2.0
switch tracktype=grade3 switch probablyGood 1.5 3.0
switch tracktype=grade4 switch probablyGood 2.0 5.0
switch tracktype=grade5 switch probablyGood 3.0 5.0
switch probablyGood 1.0 5.0
else if ( highway=track|road|path|footway ) then
(
if ( tracktype=grade1 ) then ( if probablyGood then 1.0 else 1.3 )
else if ( tracktype=grade2 ) then ( if probablyGood then 1.1 else 2.0 )
else if ( tracktype=grade3 ) then ( if probablyGood then 1.5 else 3.0 )
else if ( tracktype=grade4 ) then ( if probablyGood then 2.0 else 5.0 )
else if ( tracktype=grade5 ) then ( if probablyGood then 3.0 else 5.0 )
else ( if probablyGood then 1.0 else 5.0 )
)
#
# When avoiding unsafe ways, avoid highways without a bike hint
#
add switch and avoid_unsafe not isbike 2 0
else add ( if ( and avoid_unsafe not isbike ) then 2 else 0 )
#
# exclude motorways and proposed roads
#
switch or highway=motorway highway=motorway_link 100000
switch or highway=proposed highway=abandoned 100000
if ( highway=motorway|motorway_link ) then 100000
else if ( highway=proposed|abandoned ) then 100000
#
# actuals roads are o.k. if we have a bike hint
#
switch or highway=trunk highway=trunk_link switch isbike 1.5 10
switch or highway=primary highway=primary_link switch isbike 1.2 3
switch or highway=secondary highway=secondary_link switch isbike 1.1 1.6
switch or highway=tertiary highway=tertiary_link switch isbike 1.0 1.4
switch highway=unclassified switch isbike 1.0 1.3
else if ( highway=trunk|trunk_link ) then ( if isbike then 1.5 else 10 )
else if ( highway=primary|primary_link ) then ( if isbike then 1.2 else 3 )
else if ( highway=secondary|secondary_link ) then ( if isbike then 1.1 else 1.6 )
else if ( highway=tertiary|tertiary_link ) then ( if isbike then 1.0 else 1.4 )
else if ( highway=unclassified ) then ( if isbike then 1.0 else 1.3 )
#
# default for any other highway type not handled above
#
2.0
else 2.0
---context:node # following code refers to node tags
assign defaultaccess
switch access=
1 # add default barrier restrictions here!
switch or access=private access=no
0
1
assign defaultaccess =
if ( access= ) then true # add default barrier restrictions here!
else if ( access=private|no ) then false
else true
assign bikeaccess
or nodeaccessgranted=yes
switch bicycle=
switch vehicle=
defaultaccess
switch or vehicle=private vehicle=no
0
1
switch or bicycle=private or bicycle=no bicycle=dismount
0
1
assign bikeaccess =
if nodeaccessgranted=yes then true
else if bicycle= then
(
if vehicle= then defaultaccess
else not vehicle=private|no
)
else not bicycle=private|no|dismount
assign footaccess
or bicycle=dismount
switch foot=
defaultaccess
switch or foot=private foot=no
0
1
assign footaccess =
if bicycle=dismount then true
else if foot= then defaultaccess
else not foot=private|no
assign initialcost
switch bikeaccess
0
switch footaccess
100
1000000
assign initialcost =
if bikeaccess then 0
else ( if footaccess then 100 else 1000000 )