Skip to content

Instantly share code, notes, and snippets.

@karussell
Last active November 1, 2019 08:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save karussell/7a38acf13b2aa3a1bc8344d14d4da038 to your computer and use it in GitHub Desktop.
Save karussell/7a38acf13b2aa3a1bc8344d14d4da038 to your computer and use it in GitHub Desktop.
vehicle profile config

Loose statements

properties: compact, self-explanatory, declarative "no-loop", native yaml (?)

very specific to influence only the cost and time calculation:

calcMillis:
  time = distance_in_m / speed_in_kmh * 3.6 + delay_in_sec + turn_cost_delay_in_sec
calcWeight:
  if (isInfinity(time)) return infinity
  weight = (time + distance_in_m * distance_priority) * weight_factor

The first of the list entries matches ("haskell pattern matching") and defines the value.

Defaults are: access=false, speed=0, delay=0, priority=1 (if no encoder default exists). How to include toll cost?

If speed was set => access=true is required. Or maybe access is not required and we use isInfinity(time) instead?

For LM algo we can only decrease speed, set access to false, only increase priority and priority can be only within [0.1, 10].

Current flex branch is only able to use tags as filter and priority as factor (no complicated stuff possible):

https://gist.github.com/karussell/2fa551a9fbe8e970ac5d1e874a04a46f

We should have a look into ANTLR and a DSL like https://github.com/latera/hyaml

Open Questions

Is speed the average speed or the maximum? It is the average_speed.

What about cached EncodedValues like average_speed, access, or priority? If specified => they get overwritten and act as fallback or default.

Currently we are able to parse properties from graph.flag_encoders=car|turn_costs=true via pipe | in core. It would be nice if this moves to the profile config too. But then we would need to add jackson and yaml dependencies to core. Or should we implement a simple scripting language like done in v1.ghs that does not use many yaml features?

The big question is if we can really allow full scripting support as even with the security manager there are problems (highlighted from janino compiler author):

These are the "really evil things" that an attacker might do. However actions that are not guarded are: Allocate memory and creating new threads. Luckily, the Thread constructor does some reflection, so thread creation by scripts can be prevented by not allowing new RuntimePermission("accessDeclaredMembers"). Memory allocation can not be guarded,

  • base on an existing FlagEncoder
  • name it for import and then we could use it in a CH query

use cases:

  • allow private, delivery, destination only roads
    • if we allow a road that the base profile forbids without setting a speed there should be an exception
  • exclude roads based on max_speed value
  • slower based on incline (better foot)
  • police: allow reverse oneway or roundabout, and less strict road_access
  • add time delay instead factor should be possible too (e.g. useful to better avoid even short-distant edges)
  • first we need to define the speed and then ability to apply a factor (influenced by road_class, road_environment, surface, track_type, (smoothness?))
  • different surface values should directly correspond to a number so that we can avoid surfaces based on that somehow
  • elevation -> direction dependent slope EncodedValue
  • handle calcWeight, calcMillis, calcTollCost somehow
  • avoid crossing the border, or toll, or motorway, or ferry
  • increase speed (e-bike based on bike)
  • reduce max_speed (scooter or some e-cars based on car)
  • prefer official bike routes (increase priority influence for bike)
  • truck (based on car)
    • road_class dependent max speed
    • slower dependent on road_class
    • max_width, max_height, max_length, max_width
    • speed per road_class
    • slower on bridges (special truck)
  • block areas
  • turn_costs: true|false (later define the cost for road transition and if left|right turn)
  • u_turn_costs in seconds
  • wheelchair (based on foot)
    • never surface=sand
    • never step
# if we would have code highlighting this would be good to read and a relative simple way to express our needs
# Additionally this would be compact.
# This is probably hard to implement but we could start simple and avoid e.g. return with match functions and only use op(p1,p2,..) notation
# Also we would not be required to follow yaml restrictions and won't need yaml and jackson in the core.
# instead of strings like "ferry" we should use capital letters like FERRY
# use capital letter for enum or do not cry? 'motorway' vs. MOTORWAY
base = car
access =
max_weight > 10.7 ? false # throw exception if this edge is used for calcMillis as speed=0?
between (max_weight, 5, 6) ? true
max_weight == 10 ? true # inherit speed from car, if none set at the end => exception; throw exception if equals with doubles or should we assume 0.00001 precision or something?
speed = # allow only positive values
(road_class == "motorway") && is_inner_city? 70
delay = # allow only positive values for now
road_environment == "ferry" ? 300
priority =
road_access == "private" ? 0.01
road_access == "destination" ? ext_priority / 10 # return value is a math function
ext_priority # default matcher for all other cases that uses the EncodedValue "ext_priority" instead of the default, which is either the EncodedValue "vehicle.property" or if it does not exist it is priority==1 (specified in code)
# use line by line expressions or configurations. E.g. first match will be used.
access = road_class == motorway? true : false
speed = road_class == motorway? 120
speed = road_class == primary? 90
# the format "list: value" like "[gt, max_weight, 10.7]: false" is valid yaml
# but I didn't find a way to make jackson parse it so we could try to use the following instead? false: [gt, max_weight, 10.7]
base: car
access:
[gt, max_weight, 10.7]: false # => speed: 0
[between, max_weight, 5, 6]: true
[eq, max_weight, 10]: true # inherit speed from car, if none set at the end => exception; also throw exception if equals expression with doubles
speed:
[and, [eq, road_class, motorway], is_inner_city]: 70 # implicitly => access: true
priority:
[eq, road_access, private]: 0.01
time:
[eq, road_environment, ferry]: 300 # implicitly => access: true
# this format is not that readable but should be the easiest to implement
base: car
access:
- {p1: max_weight, op: ">", p2: 10.7, r: false} # => speed: 0
- {op: between, p1: max_weight, p2: 5, p3: 6, r: true}
- {p1: max_weight, op: "==", p2: 10, r: true} # inherit speed from car, if none set at the end => exception; also throw exception if equals expression with doubles
speed:
- {p1: {p1: road_class, p2: motorway}, op: "&&", p2: is_inner_city, r: 70} # implicitly => access: true, default op is ==
delay:
- {p1: road_environment, p2: ferry, r: 300} # implicitly => access: true
priority:
0.01 : {road_access: private} # short way for {p1: road_access, op: "==", p2: private, r: 0.01}
# a bit harder to implement with string parsing stuff
base: car
access:
- "max_weight > 10.7": false # throw exception if this edge is used for calcMillis as speed=0?
- "between (max_weight, 5, 6)": true
- "max_weight == 10": true # inherit speed from car, if none set at the end => exception; throw exception if equals with doubles or should we assume 0.00001 precision or something?
speed: # allow only positive values
- "(road_class == motorway) && is_inner_city": 70
delay: # allow only positive values for now
- "road_environment == ferry": 300
priority:
- "road_access == private": 0.01
# let's try again to create more a configuration yaml file without programming features
# also avoid access and just use priority==0 or speed==0 or speed_factor==0
base: car
weight: 2.5
# unit is meter:
height: 1.5
length: 30
max_speed: 110
# for set speed order is important: first match sets the speed and is done
# country dependent speed could be done via road_class: { de: { motorway: 100, .. }, us: { } } or road_class: { country: de, values: { motorway: 100 }
average_speed:
road_class: { motorway: 100, trunk: 95, primary: 80, secondary: 70}
surface: { sand: 30}
speed_factor:
# in priority we avoid hills, but if we go on a hill make us slower depending on the slope
# or should we differentiate uphill and downhill?
elevation: 0.5
# e.g. police can go backwards but make us slower
reverse_one_way: 0.3
# now multiply "speed" (in fact it multiples the weight only and does not modify the time)
# priority=1/weight_factor i.e. high priority means low multiplication of weight
priority:
road_environment: { ferry: 0.5 }
# for CH profile preparation we should be able to even block roads via 0 prio, but LM should do max(prio, 0.1) and return a warning in the response so that user can learn what wrong?
road_class: { motorway: 0.5, living_street: 0 }
road_access: { destination: 0.1, private: 0.1 }
toll: { no: 1.0, all: 0.1 }
# avoid cities
area: { city: 0.1, village: 0.3, custom1: 0}
official_route: { bike: 0.5, hike: 0.5}
elevation: 0.5
# police should never go reverse on highway
reverse_one_way: { motorway: 1, trunk: 1, tertiary: 0.1, residential: 0.1}
# add seconds
delay:
road_environment: { ferry: 20 }
# avoid crossing continents and allow crossing countries but add a waiting time
border: { continent: infinity, country: 7000 }
# let's define areas that can be used in e.g. set speed or factor
areas:
custom1: [list, of, coordinates, that form rectangle or polygon]
custom2: [list, of, coordinates, that form rectangle or polygon]
turn_costs:
enable: true
# should this be better in the 'delay' section?
u_turn: 40
# PS
# jackson uses snakeyaml 300kb, in 3.x 250kb
# yamlbeans 160kb
# nanojson: 30kb
# mini-yaml-parser: just 3 sources: https://bitbucket.org/ralfoide/mini-yaml-parser/src/master/Java/MiniYamlParser/src/main/com/alfray/utils/MiniYamlParser.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment