diff --git a/brouter-core/src/main/java/btools/router/OsmPath.java b/brouter-core/src/main/java/btools/router/OsmPath.java index 323156f..035c1f8 100644 --- a/brouter-core/src/main/java/btools/router/OsmPath.java +++ b/brouter-core/src/main/java/btools/router/OsmPath.java @@ -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 ) diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpression.java b/brouter-expressions/src/main/java/btools/expressions/BExpression.java index 4126a04..59bcfb4 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpression.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpression.java @@ -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 ) { diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java index 7af539f..50be710 100644 --- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java +++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContext.java @@ -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" + other.variableData[i] + + "\ntags = " + getKeyValueDescription( false, encode() ) ); + } + } + } + + private String variableName( int idx ) + { + for( Map.Entry 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 diff --git a/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java b/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java new file mode 100644 index 0000000..e525a8d --- /dev/null +++ b/brouter-expressions/src/main/java/btools/expressions/ProfileComparator.java @@ -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 " ); + 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=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 )