Profile developers guide - Technical reference
for BRouter cost-function scripts
==============================================

The tag-value lookup table
--------------------------

Within the routing data files (rd5), tag information
is encoded in a binary bitfield for the way tags and
the node tags each.

To encode and decode to/from this bitfield, a lookup
table is used that contains all the tags and values
that are considered for encoding.

For each tag there are 2 special values:

- <empty> if the tag is not set or the value is empty 
- "unknown" if the value is not contained in the table

Each value can have optional "aliases", these alias
values are encoded into the same binary value as the
associated primary value.

The numbers in the lookup table are statistical
information on the frequency of the values in the
map of germany - these are just informational and
are not processed by BRouter.

Context-Separation
------------------

Way-tags and Node-Tags are treated independently,
so there are different sections in the lookup table
as well as in the profile scripts for each context.
The special tags: "---context:way" and "---context:node"
mark the beginning of each section.

The only exception from context separation is a single
bit information "nodeaccessgranted" which is automatically
carried from the way context to the terminating node
of the way section.

In the profile scripts there is a third context "global"
which contains global configuration which is shared for
all contexts and is accessible by the routing engine.

The variables from the "global" section in the profile
scripts are read-only visible in the "way" and
"node" sections of the scripts.

Predefined variables in the profile scripts
-------------------------------------------

Some variable names are pre-defined and accessed by
the routing engine:

- for the global section these are:

  - 7 elevation configuration parameters:

    - downhillcost
    - downhillcutoff
    - uphillcost
    - uphillcutoff
    - elevationpenaltybuffer
    - elevationmaxbuffer
    - elevationbufferreduce

  - 3 boolean mode-hint flags

    - validForBikes
    - validForFoot
    - validForCars

  - 2 variables to change the heuristic
    coefficients for the 2 routing passes
    ( <0 disables a routing pass )

   - pass1coefficient
   - pass2coefficient

  - 3 variables to influence the generation of turn-instructions

   - turnInstructionMode      0=none, 1=auto-choose, 2=locus-style, 3=osmand-style
   - turnInstructionCatchingRange  default 40m
   - turnInstructionRoundabouts     default=true=generate explicit roundabout hints

- for the way section these are

  - turncost
  - initialcost
  - costfactor
  - uphillcostfactor
  - downhillcostfactor
  - nodeaccessgranted
  - initialclassifier

- for the node section this is just

  - initialcost

The operators of the profile scripts
------------------------------------

The profile scripts use polnic notation (=operator first)

The "assign" operator is special: it can be used
only on the top level of the expression hirarchy
and has 2 operands:

  assign <variable-name> <expression>

It just assigns the expression value to this
variable (which can be a predined variable or
any other variable, which in this case is defined
implicitly). The expression can be a complex expression
using other operators.

All other operators can be used recursively to an unlimted
complexity, which means that each operand can be a composed
expression starting with an operator and so on.

All expressions have one of the following basic forms:

  - <numeric>
  - <lookup-match>
  - <1-op-operator> <operand>
  - <2-op-operator> <operand> <operand>
  - <3-op-operator> <operand> <operand> <operand>

- A numeric value is just a number, floating point, with "." as
  decimal separtor. Boolean values are treated as numbers as well,
  with "0" = false and every nonzero value = true.

- A lookup match has the form <tag-name>=<value>, e.g. highway=primary
  Only the primary values can be used in lookup-matches, not aliases.
  The <empty> value is refered to as an empty string, e.g. access=

- 1 Operand operators are:

  not <boolean expression>

- 2 Operand operators are:

  or       <boolean expression 1> <boolean expression 2>
  and      <boolean expression 1> <boolean expression 2>
  xor      <boolean expression 1> <boolean expression 2>
  multiply <numeric expression 1> <numeric expression 2>
  add      <numeric expression 1> <numeric expression 2>
  sub      <numeric expression 1> <numeric expression 2>
  max      <numeric expression 1> <numeric expression 2>
  min      <numeric expression 1> <numeric expression 2>
  equal    <numeric expression 1> <numeric expression 2>
  greater  <numeric expression 1> <numeric expression 2>
  lesser   <numeric expression 1> <numeric expression 2>

- 3 Operand operators are:

  switch <boolean-expression> <true-expression> <false-expression>

  So the switch expression has a numeric value which is the
  true-expression if the boolean expression is true, the
  false-expression otherwise


Syntactic Alternatives
----------------------

To improve the readablity of the profile-scripts, some syntactic variations
are possible:

- "if then else" : "if" can be used instead of the "switch" operator, if the
  additional keywords "then" and "else" are placed between the operators:

  if <boolean-expression> then <true-expression> else <false-expression>

- Parentheses: each expression can be surrounded by parentheses: ( <expression> )
  Please note that the profile syntax, due to the polnic notation, does not
  need parentheses, they are always optional. However, if there are parentheses,
  the parser checks if they really match the expression boundaries.

- or-ing lookup-matches: the pipe-symbol can be used as a short syntax for
  lookup matches where more than one value is accepted for a key:
  highway=primary|secondary|tertiary

- additional "=" symbol for "assign"operations:
  assign <variable-name> = <expression>

- boolean constants: "true" and "false" can be used instead of 1 and 0

Please note the the tokenizer always expects blank space to separate
symbols and expressions so it is not allowed to places parentheses or
the "=" symbol without separating blank space!


The initial cost classifier
---------------------------

To trigger the addition of the "initialcost", another variable is used:
"initialclassifier" - any change in the value of that variable leads
to adding the value of "initialcost".
For backward compatibility, if "initialclassifier"  = 0, it is replaced
by the costfactor.


Technical constraints
---------------------

- The costfactor is required to be >= 1, otherwise the cost-cutoff
  logic of the routing algorithm does not work and you get wrong results.

- The profile should be able to find a route with an average costfactor
  not very much larger than one, because otherwise the routing algorithm
  will not find a reasonable cost-cutoff, leading to a very large
  search area and thus to long processing times.

- Forbidden ways or nodes must be treated as very high cost, because
  there is no "forbidden" value. Technically, values >= 10000. for a
  (way-)costfactor, and >=1000000. for a nodes "initalcost" are treated
  as infinity, so please use these as the "forbidden" values.


Developing and debugging scripts
--------------------------------

For developing scripts, the "brouter-web" web-application is your
friend. You can use that either online at http://brouter/brouter-web
or set up a local installation.
BRouter-Web has a window at the lower left corner with a "Profile"
and a "Data" tab. Here, you can upload profile scripts and see
the individual cost calculations per way-section in the "Data"-tab.


Lookup-Table evolution and the the "major" and "minor" versions
---------------------------------------------------------------

The lookup-table is allowed to grow over time, to include more tags
and values as needed. To support that evolution, it carries a major
and a minor version number. These numbers are also encoded into
the routing data files, taken from the lookups.dat that is used
to pre-process the routing data files.

A major version change is considered to always break compatibiliy
between the routing datafiles and the lookup table.

A minor version change keeps the routing data files and the lookup-table
compatible in the following way:

If the minor version from the routing data file is equal OR LARGER
than the minor version in the lookup table, everything is o.k.
This is the case, if you get updated data files, but don't update
the lookup-table of your local installation.

If the lookup-tables's minor version is larger than that in the the
data files, you will get an error message.

Note that for an update of the Android app, your local lookup-table is NOT
replaced by the new version. The new lookup table is contained inside
the APK, but is not automatically copied to your sd-card if there
is already a local installation. This is to prevent invalidating
your routing data files due to software updates. However, in order
to make use of the new tags and values in a new software version, you
have to delete (or rename) your "profiles2" directory, so the new
content from the APK file is copied to the sd-card at next start.

For a minor version change it is required that tags are only
appended at the end of the table (or replace one of the dummy
tags located between the way-tags and the relation pseudo-tags),
and that values are only appended at the end of the value lists.
This is because the routing data files adress tags and values
by their sequence numbers, so changing sequences would produce
garbage data.
